├── .github └── workflows │ ├── ci.yml │ ├── conventional-commits.yml │ ├── python-core-wheels.yml │ ├── python-docs.yml │ ├── python-io-wheels.yml │ ├── python.yml │ └── wasm.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE_APACHE ├── LICENSE_MIT ├── README.md ├── build ├── .gitattributes ├── .gitignore ├── README.md ├── pixi.lock └── pixi.toml ├── docs ├── .gitignore ├── .python-version ├── README.md ├── mkdocs.yml ├── pyproject.toml ├── source │ ├── index.md │ ├── rust.md │ └── stylesheets │ │ └── extra.css └── uv.lock ├── fixtures ├── README.md ├── flatgeobuf │ ├── README.md │ ├── alldatatypes.fgb │ ├── countries.fgb │ ├── nz-building-outlines-small.fgb │ ├── poly00.fgb │ └── poly01.fgb ├── geoparquet │ ├── generate_data.py │ ├── nybb.parquet │ ├── nybb_geoarrow.parquet │ ├── nybb_wkb.parquet │ ├── nybb_wkb_covering.parquet │ ├── overture_buildings.parquet │ └── overture_infrastructure.parquet ├── nybb.arrow └── roads.geojson ├── js ├── .gitignore ├── .travis.yml ├── .yarnrc.yml ├── Cargo.lock ├── Cargo.toml ├── DEVELOP.md ├── LICENSE_APACHE ├── LICENSE_MIT ├── README.md ├── RELEASE.md ├── build │ └── modules │ │ ├── flatgeobuf-wasm │ │ ├── README.md │ │ └── build.sh │ │ └── geoparquet-wasm │ │ ├── README.md │ │ └── build.sh ├── package.json ├── scripts │ └── build.sh ├── src │ ├── algorithm │ │ ├── geo │ │ │ ├── affine_ops.rs │ │ │ ├── area.rs │ │ │ ├── bounding_rect.rs │ │ │ ├── center.rs │ │ │ ├── centroid.rs │ │ │ ├── chaikin_smoothing.rs │ │ │ ├── chamberlain_duquette_area.rs │ │ │ ├── contains.rs │ │ │ ├── convex_hull.rs │ │ │ ├── densify.rs │ │ │ ├── dimensions.rs │ │ │ ├── euclidean_length.rs │ │ │ ├── geodesic_area.rs │ │ │ ├── geodesic_length.rs │ │ │ ├── haversine_length.rs │ │ │ ├── mod.rs │ │ │ ├── rotate.rs │ │ │ ├── scale.rs │ │ │ ├── simplify.rs │ │ │ ├── simplify_vw.rs │ │ │ ├── skew.rs │ │ │ ├── translate.rs │ │ │ └── vincenty_length.rs │ │ ├── geoarrow │ │ │ ├── coord_format.rs │ │ │ └── mod.rs │ │ └── mod.rs │ ├── data │ │ ├── coord.rs │ │ └── mod.rs │ ├── data_type.rs │ ├── dimension.rs │ ├── error.rs │ ├── ffi │ │ ├── mod.rs │ │ └── to_ffi │ │ │ ├── data.rs │ │ │ ├── mod.rs │ │ │ └── vector.rs │ ├── io │ │ ├── flatgeobuf.rs │ │ ├── geojson.rs │ │ ├── mod.rs │ │ ├── object_store.rs │ │ ├── object_store_s3 │ │ │ └── mod.rs │ │ └── parquet │ │ │ ├── async.rs │ │ │ ├── async_file_reader │ │ │ ├── fetch.rs │ │ │ └── mod.rs │ │ │ ├── mod.rs │ │ │ ├── options.rs │ │ │ └── sync.rs │ ├── lib.rs │ ├── reproject.rs │ ├── scalar │ │ ├── linestring.rs │ │ ├── mod.rs │ │ ├── multilinestring.rs │ │ ├── multipoint.rs │ │ ├── multipolygon.rs │ │ ├── point.rs │ │ └── polygon.rs │ ├── transform_origin.rs │ ├── utils.rs │ └── vector.rs ├── tests │ ├── js │ │ ├── example.test.ts │ │ ├── flatgeobuf.test.ts │ │ └── geoparquet.test.ts │ └── web.rs ├── tsconfig.docs.json ├── tsconfig.json ├── typedoc.json └── yarn.lock ├── python ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── DEVELOP.md ├── README.md ├── docs │ ├── CHANGELOG.md │ ├── DEVELOP.md │ ├── api │ │ ├── compute │ │ │ ├── enums.md │ │ │ ├── functions.md │ │ │ └── types.md │ │ ├── core │ │ │ ├── array.md │ │ │ ├── chunked_array.md │ │ │ ├── constructors.md │ │ │ ├── enums.md │ │ │ ├── functions.md │ │ │ ├── geometry │ │ │ │ ├── scalar.md │ │ │ │ └── type.md │ │ │ ├── geometry_type.md │ │ │ ├── index.md │ │ │ └── types.md │ │ └── io │ │ │ ├── arrow_ipc.md │ │ │ ├── csv.md │ │ │ ├── flatgeobuf.md │ │ │ ├── gdal.md │ │ │ ├── geojson.md │ │ │ ├── geoparquet.md │ │ │ ├── postgis.md │ │ │ └── shapefile.md │ ├── ecosystem │ │ ├── geopandas.md │ │ ├── lonboard.md │ │ ├── pyogrio.md │ │ └── shapely.md │ ├── index.md │ └── stylesheets │ │ └── extra.css ├── examples │ └── overture_buildings.ipynb ├── geoarrow-compute │ ├── Cargo.toml │ ├── README.md │ ├── pyproject.toml │ ├── python │ │ └── geoarrow │ │ │ └── rust │ │ │ └── compute │ │ │ ├── __init__.py │ │ │ ├── _compute.pyi │ │ │ ├── enums.py │ │ │ ├── py.typed │ │ │ └── types.py │ └── src │ │ ├── algorithm │ │ ├── geo │ │ │ ├── affine_ops.rs │ │ │ ├── area.rs │ │ │ ├── center.rs │ │ │ ├── centroid.rs │ │ │ ├── chaikin_smoothing.rs │ │ │ ├── convex_hull.rs │ │ │ ├── densify.rs │ │ │ ├── dimensions.rs │ │ │ ├── envelope.rs │ │ │ ├── frechet_distance.rs │ │ │ ├── geodesic_area.rs │ │ │ ├── length.rs │ │ │ ├── line_interpolate_point.rs │ │ │ ├── line_locate_point.rs │ │ │ ├── mod.rs │ │ │ ├── rotate.rs │ │ │ ├── scale.rs │ │ │ ├── simplify.rs │ │ │ ├── skew.rs │ │ │ └── translate.rs │ │ ├── mod.rs │ │ ├── native │ │ │ ├── explode.rs │ │ │ ├── mod.rs │ │ │ └── total_bounds.rs │ │ └── polylabel.rs │ │ ├── ffi │ │ ├── from_python │ │ │ ├── input.rs │ │ │ └── mod.rs │ │ └── mod.rs │ │ ├── lib.rs │ │ └── util.rs ├── geoarrow-core │ ├── Cargo.lock │ ├── Cargo.toml │ ├── DEVELOP.md │ ├── README.md │ ├── pyproject.toml │ ├── python │ │ └── geoarrow │ │ │ └── rust │ │ │ └── core │ │ │ ├── __init__.py │ │ │ ├── _array.pyi │ │ │ ├── _array_reader.pyi │ │ │ ├── _chunked_array.pyi │ │ │ ├── _constructors.pyi │ │ │ ├── _crs.py │ │ │ ├── _data_type.pyi │ │ │ ├── _rust.pyi │ │ │ ├── _scalar.pyi │ │ │ ├── enums.py │ │ │ ├── py.typed │ │ │ └── types.py │ └── src │ │ ├── constructors.rs │ │ ├── ffi │ │ ├── from_python │ │ │ ├── input.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── to_python │ │ │ ├── array.rs │ │ │ └── mod.rs │ │ ├── interop │ │ ├── geopandas │ │ │ ├── from_geopandas.rs │ │ │ ├── mod.rs │ │ │ └── to_geopandas.rs │ │ ├── mod.rs │ │ ├── numpy │ │ │ ├── mod.rs │ │ │ └── to_numpy.rs │ │ ├── pyogrio │ │ │ ├── from_pyogrio.rs │ │ │ └── mod.rs │ │ ├── shapely │ │ │ ├── from_shapely.rs │ │ │ ├── mod.rs │ │ │ ├── to_shapely.rs │ │ │ └── utils.rs │ │ ├── util.rs │ │ ├── wkb.rs │ │ └── wkt.rs │ │ ├── lib.rs │ │ └── table │ │ ├── geo_interface.rs │ │ └── mod.rs ├── geoarrow-io │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── pyproject.toml │ ├── python │ │ └── geoarrow │ │ │ └── rust │ │ │ └── io │ │ │ ├── __init__.py │ │ │ ├── _csv.pyi │ │ │ ├── _flatgeobuf.pyi │ │ │ ├── _geojson.pyi │ │ │ ├── _io.pyi │ │ │ ├── _parquet.pyi │ │ │ ├── _postgis.pyi │ │ │ ├── _shapefile.pyi │ │ │ ├── enums.py │ │ │ ├── py.typed │ │ │ └── types.py │ └── src │ │ ├── error.rs │ │ ├── input │ │ ├── mod.rs │ │ └── sync.rs │ │ ├── io │ │ ├── csv.rs │ │ ├── flatgeobuf │ │ │ ├── async.rs │ │ │ ├── mod.rs │ │ │ └── sync.rs │ │ ├── geojson.rs │ │ ├── geojson_lines.rs │ │ ├── mod.rs │ │ ├── postgis.rs │ │ └── shapefile.rs │ │ ├── lib.rs │ │ ├── parquet │ │ ├── async.rs │ │ ├── mod.rs │ │ ├── options.rs │ │ └── sync.rs │ │ └── runtime.rs ├── metapackage │ ├── DEVELOP.md │ ├── README.md │ └── pyproject.toml ├── mkdocs.yml ├── proj │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── pyproject.toml │ ├── python │ │ └── geoarrow │ │ │ └── rust │ │ │ └── proj │ │ │ ├── __init__.py │ │ │ └── py.typed │ └── src │ │ └── lib.rs ├── pyproject.toml ├── tests │ ├── __init__.py │ ├── core │ │ ├── __init__.py │ │ ├── test_array.py │ │ ├── test_chunked_array.py │ │ ├── test_crs.py │ │ ├── test_scalar.py │ │ └── test_type.py │ ├── io │ │ └── test_flatgeobuf.py │ └── utils.py ├── tests_old │ ├── __init__.py │ ├── algorithm │ │ ├── __init__.py │ │ ├── test_affine_ops.py │ │ ├── test_area.py │ │ └── test_explode.py │ ├── core │ │ ├── __init__.py │ │ ├── test_array.py │ │ ├── test_constructors.py │ │ └── test_geometry_type.py │ ├── interop │ │ ├── __init__.py │ │ ├── test_geopandas.py │ │ ├── test_shapely.py │ │ ├── test_wkb.py │ │ └── test_wkt.py │ ├── io │ │ ├── __init__.py │ │ ├── test_csv.py │ │ ├── test_flatgeobuf.py │ │ ├── test_geoparquet.py │ │ ├── test_pyogrio.py │ │ └── test_shapefile.py │ └── utils.py └── uv.lock └── rust ├── README.md ├── geoarrow-array ├── Cargo.toml ├── README.md └── src │ ├── array │ ├── coord │ │ ├── combined.rs │ │ ├── interleaved.rs │ │ ├── mod.rs │ │ └── separated.rs │ ├── geometry.rs │ ├── geometrycollection.rs │ ├── linestring.rs │ ├── mixed.rs │ ├── mod.rs │ ├── multilinestring.rs │ ├── multipoint.rs │ ├── multipolygon.rs │ ├── point.rs │ ├── polygon.rs │ ├── rect.rs │ ├── wkb.rs │ ├── wkb_view.rs │ ├── wkt.rs │ └── wkt_view.rs │ ├── builder │ ├── coord │ │ ├── combined.rs │ │ ├── interleaved.rs │ │ ├── mod.rs │ │ └── separated.rs │ ├── geo_trait_wrappers.rs │ ├── geometry.rs │ ├── geometrycollection.rs │ ├── linestring.rs │ ├── mixed.rs │ ├── mod.rs │ ├── multilinestring.rs │ ├── multipoint.rs │ ├── multipolygon.rs │ ├── offsets.rs │ ├── point.rs │ ├── polygon.rs │ ├── rect.rs │ └── wkb.rs │ ├── capacity │ ├── geometry.rs │ ├── geometrycollection.rs │ ├── linestring.rs │ ├── mixed.rs │ ├── mod.rs │ ├── multilinestring.rs │ ├── multipoint.rs │ ├── multipolygon.rs │ ├── point.rs │ ├── polygon.rs │ └── wkb.rs │ ├── cast.rs │ ├── eq.rs │ ├── geozero │ ├── export │ │ ├── array │ │ │ ├── geometry.rs │ │ │ ├── geometrycollection.rs │ │ │ ├── linestring.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ ├── polygon.rs │ │ │ ├── rect.rs │ │ │ ├── wkb.rs │ │ │ └── wkt.rs │ │ ├── data_source │ │ │ ├── mod.rs │ │ │ └── record_batch_reader.rs │ │ ├── mod.rs │ │ └── scalar │ │ │ ├── coord.rs │ │ │ ├── geometry.rs │ │ │ ├── geometry_collection.rs │ │ │ ├── linestring.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ ├── polygon.rs │ │ │ └── rect.rs │ ├── import │ │ ├── geometry.rs │ │ ├── linestring.rs │ │ ├── mod.rs │ │ ├── multilinestring.rs │ │ ├── multipoint.rs │ │ ├── multipolygon.rs │ │ ├── point.rs │ │ ├── polygon.rs │ │ └── util.rs │ └── mod.rs │ ├── lib.rs │ ├── scalar │ ├── coord │ │ ├── combined.rs │ │ ├── interleaved.rs │ │ ├── mod.rs │ │ └── separated.rs │ ├── geometry.rs │ ├── geometrycollection.rs │ ├── linestring.rs │ ├── mod.rs │ ├── multilinestring.rs │ ├── multipoint.rs │ ├── multipolygon.rs │ ├── point.rs │ ├── polygon.rs │ ├── rect.rs │ └── specialization.rs │ ├── test │ ├── geometry.rs │ ├── geometrycollection.rs │ ├── linestring.rs │ ├── mod.rs │ ├── multilinestring.rs │ ├── multipoint.rs │ ├── multipolygon.rs │ ├── point.rs │ ├── polygon.rs │ ├── properties.rs │ └── rect.rs │ ├── trait_.rs │ └── util.rs ├── geoarrow-cast ├── Cargo.toml ├── README.md └── src │ ├── cast.rs │ ├── downcast.rs │ └── lib.rs ├── geoarrow-flatgeobuf ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ └── writer.rs ├── geoarrow-geos ├── Cargo.toml ├── README.md └── src │ ├── export │ ├── mod.rs │ └── scalar │ │ ├── coord.rs │ │ ├── geometry.rs │ │ ├── geometrycollection.rs │ │ ├── linestring.rs │ │ ├── mod.rs │ │ ├── multilinestring.rs │ │ ├── multipoint.rs │ │ ├── multipolygon.rs │ │ ├── point.rs │ │ └── polygon.rs │ ├── import │ ├── array │ │ ├── geometry.rs │ │ ├── geometrycollection.rs │ │ ├── linestring.rs │ │ ├── mod.rs │ │ ├── multilinestring.rs │ │ ├── multipoint.rs │ │ ├── multipolygon.rs │ │ ├── point.rs │ │ ├── polygon.rs │ │ └── wkb.rs │ ├── mod.rs │ └── scalar │ │ ├── coord.rs │ │ ├── geometry.rs │ │ ├── geometrycollection.rs │ │ ├── linearring.rs │ │ ├── linestring.rs │ │ ├── mod.rs │ │ ├── multilinestring.rs │ │ ├── multipoint.rs │ │ ├── multipolygon.rs │ │ ├── point.rs │ │ └── polygon.rs │ └── lib.rs ├── geoarrow-schema ├── Cargo.toml ├── README.md └── src │ ├── coord_type.rs │ ├── crs.rs │ ├── datatype.rs │ ├── dimension.rs │ ├── edges.rs │ ├── error.rs │ ├── lib.rs │ ├── metadata.rs │ └── type.rs ├── geoarrow-test ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ └── raw │ ├── geometry.rs │ ├── geometrycollection.rs │ ├── linestring.rs │ ├── mod.rs │ ├── multilinestring.rs │ ├── multipoint.rs │ ├── multipolygon.rs │ ├── point.rs │ └── polygon.rs ├── geoarrow ├── Cargo.toml ├── benches │ ├── area.rs │ ├── from_geo.rs │ ├── geos_buffer.rs │ ├── nybb.rs │ ├── translate.rs │ └── wkb.rs ├── examples │ ├── README.md │ └── gdal.rs ├── fixtures └── src │ ├── algorithm │ ├── broadcasting │ │ ├── geometry.rs │ │ ├── linestring.rs │ │ ├── mod.rs │ │ ├── multilinestring.rs │ │ ├── multipoint.rs │ │ ├── multipolygon.rs │ │ ├── point.rs │ │ ├── polygon.rs │ │ ├── primitive.rs │ │ └── vec.rs │ ├── geo │ │ ├── affine_ops.rs │ │ ├── area.rs │ │ ├── bounding_rect.rs │ │ ├── center.rs │ │ ├── centroid.rs │ │ ├── chaikin_smoothing.rs │ │ ├── chamberlain_duquette_area.rs │ │ ├── concave_hull.rs │ │ ├── contains.rs │ │ ├── convex_hull.rs │ │ ├── densify.rs │ │ ├── dimensions.rs │ │ ├── euclidean_distance.rs │ │ ├── euclidean_length.rs │ │ ├── frechet_distance.rs │ │ ├── geodesic_area.rs │ │ ├── geodesic_length.rs │ │ ├── haversine_length.rs │ │ ├── interior_point.rs │ │ ├── intersects.rs │ │ ├── line_interpolate_point.rs │ │ ├── line_locate_point.rs │ │ ├── minimum_rotated_rect.rs │ │ ├── mod.rs │ │ ├── remove_repeated_points.rs │ │ ├── rotate.rs │ │ ├── scale.rs │ │ ├── simplify.rs │ │ ├── simplify_vw.rs │ │ ├── simplify_vw_preserve.rs │ │ ├── skew.rs │ │ ├── translate.rs │ │ ├── utils.rs │ │ ├── vincenty_length.rs │ │ └── within.rs │ ├── geo_index │ │ ├── mod.rs │ │ └── rtree.rs │ ├── geodesy │ │ ├── mod.rs │ │ └── reproject.rs │ ├── geos │ │ ├── area.rs │ │ ├── bool_ops.rs │ │ ├── buffer.rs │ │ ├── is_empty.rs │ │ ├── is_ring.rs │ │ ├── is_simple.rs │ │ ├── is_valid.rs │ │ ├── length.rs │ │ ├── mod.rs │ │ └── util.rs │ ├── mod.rs │ ├── native │ │ ├── binary.rs │ │ ├── bounding_rect.rs │ │ ├── cast.rs │ │ ├── concatenate.rs │ │ ├── downcast.rs │ │ ├── eq.rs │ │ ├── explode.rs │ │ ├── map_chunks.rs │ │ ├── map_coords.rs │ │ ├── mod.rs │ │ ├── rechunk.rs │ │ ├── take.rs │ │ ├── total_bounds.rs │ │ ├── type_id.rs │ │ └── unary.rs │ ├── polylabel.rs │ ├── proj.rs │ └── rstar.rs │ ├── error.rs │ ├── indexed │ ├── array.rs │ ├── chunked.rs │ └── mod.rs │ ├── io │ ├── crs.rs │ ├── csv │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── writer.rs │ ├── display │ │ ├── array.rs │ │ ├── chunked_array.rs │ │ ├── mod.rs │ │ ├── scalar.rs │ │ └── table.rs │ ├── flatgeobuf │ │ ├── mod.rs │ │ └── reader │ │ │ ├── async.rs │ │ │ ├── common.rs │ │ │ ├── mod.rs │ │ │ ├── object_store_reader.rs │ │ │ └── sync.rs │ ├── gdal │ │ ├── mod.rs │ │ └── reader.rs │ ├── geo.rs │ ├── geojson │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── writer.rs │ ├── geojson_lines │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── writer.rs │ ├── geos │ │ ├── array │ │ │ ├── binary.rs │ │ │ ├── geometrycollection.rs │ │ │ ├── linestring.rs │ │ │ ├── mixed.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ └── polygon.rs │ │ ├── mod.rs │ │ └── scalar │ │ │ ├── binary.rs │ │ │ ├── coord │ │ │ ├── combined.rs │ │ │ ├── interleaved.rs │ │ │ ├── mod.rs │ │ │ └── separated.rs │ │ │ ├── geometry.rs │ │ │ ├── geometrycollection.rs │ │ │ ├── linearring.rs │ │ │ ├── linestring.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ └── polygon.rs │ ├── geozero │ │ ├── array │ │ │ ├── dynamic.rs │ │ │ ├── geometry.rs │ │ │ ├── geometrycollection.rs │ │ │ ├── linestring.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ └── polygon.rs │ │ ├── mod.rs │ │ ├── scalar │ │ │ ├── binary.rs │ │ │ ├── coord.rs │ │ │ ├── geometry.rs │ │ │ ├── geometry_array.rs │ │ │ ├── geometry_collection.rs │ │ │ ├── linestring.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ └── polygon.rs │ │ └── table │ │ │ ├── builder │ │ │ ├── anyvalue.rs │ │ │ ├── mod.rs │ │ │ ├── properties.rs │ │ │ └── table.rs │ │ │ ├── data_source.rs │ │ │ ├── json_encoder.rs │ │ │ └── mod.rs │ ├── ipc │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── writer.rs │ ├── mod.rs │ ├── postgis │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── type_info.rs │ ├── shapefile │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── scalar.rs │ ├── stream.rs │ ├── wkb │ │ ├── api.rs │ │ ├── mod.rs │ │ ├── reader │ │ │ └── type.rs │ │ └── writer │ │ │ ├── geometry.rs │ │ │ ├── geometrycollection.rs │ │ │ ├── linestring.rs │ │ │ ├── mod.rs │ │ │ ├── multilinestring.rs │ │ │ ├── multipoint.rs │ │ │ ├── multipolygon.rs │ │ │ ├── point.rs │ │ │ ├── polygon.rs │ │ │ └── rect.rs │ └── wkt │ │ ├── mod.rs │ │ ├── reader.rs │ │ └── writer.rs │ ├── lib.rs │ ├── table.rs │ └── trait_.rs ├── geodatafusion ├── Cargo.toml ├── README.md └── src │ ├── data_types.rs │ ├── error.rs │ ├── lib.rs │ └── udf │ ├── mod.rs │ └── native │ ├── accessors │ ├── coord_dim.rs │ ├── envelope.rs │ ├── line_string.rs │ └── mod.rs │ ├── bounding_box │ ├── box_2d.rs │ ├── expand.rs │ ├── extrema.rs │ ├── make_box_2d.rs │ └── mod.rs │ ├── constructors │ ├── mod.rs │ └── point.rs │ ├── io │ ├── geohash.rs │ ├── mod.rs │ ├── wkb.rs │ └── wkt.rs │ ├── measurement │ ├── area.rs │ └── mod.rs │ ├── mod.rs │ └── processing │ ├── centroid.rs │ ├── chaikin_smoothing.rs │ ├── concave_hull.rs │ ├── convex_hull.rs │ ├── mod.rs │ ├── point_on_surface.rs │ ├── simplify.rs │ ├── simplify_preserve_topology.rs │ └── simplify_vw.rs ├── geoparquet ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ ├── metadata.rs │ ├── reader │ ├── README.md │ ├── async.rs │ ├── geo_ext.rs │ ├── metadata.rs │ ├── mod.rs │ ├── parse.rs │ ├── spatial_filter.rs │ └── sync.rs │ ├── test │ ├── geoarrow_data │ │ ├── example.rs │ │ ├── example_crs.rs │ │ └── mod.rs │ ├── mod.rs │ └── test.rs │ ├── total_bounds.rs │ └── writer │ ├── async.rs │ ├── encode.rs │ ├── metadata.rs │ ├── mod.rs │ ├── options.rs │ └── sync.rs └── pyo3-geoarrow ├── Cargo.toml ├── README.md └── src ├── array.rs ├── array_reader.rs ├── chunked_array.rs ├── coord_buffer.rs ├── coord_type.rs ├── crs.rs ├── data_type.rs ├── dimension.rs ├── edges.rs ├── error.rs ├── ffi ├── from_python │ ├── mod.rs │ └── scalar.rs └── mod.rs ├── lib.rs ├── offset_buffer.rs └── scalar ├── bounding_rect.rs └── mod.rs /.github/workflows/conventional-commits.yml: -------------------------------------------------------------------------------- 1 | name: PR Conventional Commit Validation 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, synchronize, reopened, edited] 6 | 7 | jobs: 8 | validate-pr-title: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: PR Conventional Commit Validation 12 | uses: ytanikin/pr-conventional-commits@1.4.0 13 | with: 14 | task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert"]' 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | emsdk 2 | vcpkg 3 | vcpkg_installed 4 | .pyodide* 5 | 6 | *.whl 7 | *.DS_Store 8 | .idea 9 | 10 | # Generated by Cargo 11 | # will have compiled files and executables 12 | debug/ 13 | target/ 14 | 15 | # These are backup files generated by rustfmt 16 | **/*.rs.bk 17 | 18 | # MSVC Windows builds of rustc generate these, which store debugging information 19 | *.pdb 20 | 21 | *.fgb 22 | *.arrow* 23 | *.parquet 24 | .vscode 25 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "fixtures/geoarrow-data"] 2 | path = fixtures/geoarrow-data 3 | url = https://github.com/geoarrow/geoarrow-data 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Get [rust](https://rustup.rs/). 4 | Then: 5 | 6 | ```shell 7 | git clone git@github.com:geoarrow/geoarrow-rs.git 8 | cd geoarrow-rs 9 | cargo test --all-features 10 | ``` 11 | 12 | Use Github [pull requests](https://github.com/geoarrow/geoarrow-rs/pulls) to provide code and documentation. 13 | Use [issues](https://github.com/geoarrow/geoarrow-rs/issues) to report bugs or request features. 14 | 15 | ## Build issues 16 | 17 | If you get the following error: 18 | 19 | ```text 20 | CMake Error at cmake/Ccache.cmake:10 (cmake_minimum_required): 21 | Compatibility with CMake < 3.5 has been removed from CMake. 22 | 23 | Update the VERSION argument value. Or, use the ... syntax 24 | to tell CMake that the project requires at least but has been updated 25 | to work with policies introduced by or earlier. 26 | 27 | Or, add -DCMAKE_POLICY_VERSION_MINIMUM=3.5 to try configuring anyway. 28 | Call Stack (most recent call first): 29 | CMakeLists.txt:130 (include) 30 | ``` 31 | 32 | Fix by following those instructions: 33 | 34 | ```shell 35 | export CMAKE_POLICY_VERSION_MINIMUM=3.5 36 | cargo test --all-features 37 | ``` 38 | -------------------------------------------------------------------------------- /LICENSE_MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Kyle Barron 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build/.gitattributes: -------------------------------------------------------------------------------- 1 | # GitHub syntax highlighting 2 | pixi.lock linguist-language=YAML 3 | -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | # pixi environments 2 | .pixi 3 | -------------------------------------------------------------------------------- /build/README.md: -------------------------------------------------------------------------------- 1 | # Build support 2 | 3 | geoarrow-rs depends on a number of optional C dependencies, such as GEOS, PROJ, and GDAL. To simplify these dependencies, we use [Pixi](https://github.com/prefix-dev/pixi), a package management system for native dependencies with an easy-to-use lockfile. 4 | 5 | ``` 6 | cargo install pixi 7 | pixi install 8 | pixi shell 9 | ``` 10 | 11 | You can also update your local environment variables by running this from the repo root. 12 | 13 | ```bash 14 | export GDAL_HOME="$(pwd)/build/.pixi/envs/default" 15 | export LD_LIBRARY_PATH="$(pwd)/build/.pixi/envs/default/lib:$LD_LIBRARY_PATH" 16 | export GEOS_LIB_DIR="$(pwd)/build/.pixi/envs/default/lib:$GEOS_LIB_DIR" 17 | export GEOS_VERSION=3.12.1 18 | export PKG_CONFIG_PATH="$(pwd)/build/.pixi/envs/default/lib/pkgconfig:$PKG_CONFIG_PATH" 19 | ``` 20 | -------------------------------------------------------------------------------- /build/pixi.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "rust-build" 3 | version = "0.1.0" 4 | description = "Add a short description here" 5 | authors = ["Kyle Barron "] 6 | channels = ["conda-forge"] 7 | platforms = ["osx-arm64", "linux-64"] 8 | 9 | [tasks] 10 | 11 | [dependencies] 12 | libgdal = ">=3.8" 13 | geos = ">=3.12.1" 14 | protobuf = "4.23.4.*" 15 | proj = ">=9.3.1" 16 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | -------------------------------------------------------------------------------- /docs/.python-version: -------------------------------------------------------------------------------- 1 | 3.11 2 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Top-level documentation website 2 | 3 | Mkdocs-based website to serve as high-level website and refer people to language-specific documentation. 4 | 5 | To build website: 6 | 7 | ``` 8 | uv run mkdocs serve 9 | ``` 10 | 11 | To deploy: We have a couple manual steps because `mkdocs gh-deploy` _replaces_ 12 | any existing content on the `gh-pages` branch and we want an _upsert_ that 13 | doesn't touch the `js/` or `python/` directories, which are deployed separately. 14 | 15 | ```bash 16 | uv run mkdocs build 17 | git checkout gh-pages 18 | cd .. 19 | git pull 20 | rm -rf 404.html assets index.html sitemap.xml sitemap.xml.gz search stylesheets 21 | mv -f docs/site/* ./ 22 | git add 404.html assets index.html sitemap.xml sitemap.xml.gz search stylesheets rust 23 | git commit -m "New revision of top-level docs site" 24 | git push 25 | # Return to previous branch 26 | git checkout - 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "docs" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.11" 7 | dependencies = [] 8 | 9 | [tool.uv] 10 | dev-dependencies = [ 11 | "mkdocs>=1.6.1", 12 | "mkdocs-material[imaging]>=9.5.40", 13 | "pymdown-extensions>=10.11.2", 14 | ] 15 | -------------------------------------------------------------------------------- /docs/source/rust.md: -------------------------------------------------------------------------------- 1 | ../../rust/README.md -------------------------------------------------------------------------------- /docs/source/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | [data-md-color-scheme="rust-light"] { 2 | --md-primary-fg-color: #dea584; 3 | --md-primary-bg-color: #1f292d; 4 | --md-primary-fg-color--light: #f9c6a9; 5 | --md-primary-fg-color--dark: #c28a6a; 6 | } 7 | 8 | /* Override just a couple colors from slate */ 9 | [data-md-color-scheme="slate"] { 10 | --md-primary-fg-color: #dea584; 11 | --md-primary-bg-color: #1f292d; 12 | --md-primary-fg-color--light: #f9c6a9; 13 | --md-primary-fg-color--dark: #c28a6a; 14 | } 15 | -------------------------------------------------------------------------------- /fixtures/flatgeobuf/README.md: -------------------------------------------------------------------------------- 1 | - https://github.com/flatgeobuf/flatgeobuf/blob/2876fac0456775199a061313d7d6fcc0b6f338c7/test/data/countries.fgb 2 | - https://raw.githubusercontent.com/flatgeobuf/flatgeobuf/master/test/data/countries.fgb 3 | 4 | 5 | ### `nz-building-outlines-small.fgb` 6 | 7 | ``` 8 | ogr2ogr nz-building-outlines-small.fgb /vsicurl/https://storage.googleapis.com/open-geodata/linz-examples/nz-building-outlines.parquet -limit 2000 9 | ``` 10 | -------------------------------------------------------------------------------- /fixtures/flatgeobuf/alldatatypes.fgb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/flatgeobuf/alldatatypes.fgb -------------------------------------------------------------------------------- /fixtures/flatgeobuf/countries.fgb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/flatgeobuf/countries.fgb -------------------------------------------------------------------------------- /fixtures/flatgeobuf/nz-building-outlines-small.fgb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/flatgeobuf/nz-building-outlines-small.fgb -------------------------------------------------------------------------------- /fixtures/flatgeobuf/poly00.fgb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/flatgeobuf/poly00.fgb -------------------------------------------------------------------------------- /fixtures/flatgeobuf/poly01.fgb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/flatgeobuf/poly01.fgb -------------------------------------------------------------------------------- /fixtures/geoparquet/generate_data.py: -------------------------------------------------------------------------------- 1 | import geodatasets 2 | import geopandas as gpd 3 | 4 | nybb = gpd.read_file(geodatasets.get_path("nybb")) 5 | nybb.to_parquet("nybb_wkb.parquet", geometry_encoding="WKB") 6 | nybb.to_parquet( 7 | "nybb_wkb_covering.parquet", geometry_encoding="WKB", write_covering_bbox=True 8 | ) 9 | nybb.to_parquet("nybb_geoarrow.parquet", geometry_encoding="geoarrow") 10 | -------------------------------------------------------------------------------- /fixtures/geoparquet/nybb.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/geoparquet/nybb.parquet -------------------------------------------------------------------------------- /fixtures/geoparquet/nybb_geoarrow.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/geoparquet/nybb_geoarrow.parquet -------------------------------------------------------------------------------- /fixtures/geoparquet/nybb_wkb.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/geoparquet/nybb_wkb.parquet -------------------------------------------------------------------------------- /fixtures/geoparquet/nybb_wkb_covering.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/geoparquet/nybb_wkb_covering.parquet -------------------------------------------------------------------------------- /fixtures/geoparquet/overture_buildings.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/geoparquet/overture_buildings.parquet -------------------------------------------------------------------------------- /fixtures/geoparquet/overture_infrastructure.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/geoparquet/overture_infrastructure.parquet -------------------------------------------------------------------------------- /fixtures/nybb.arrow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/fixtures/nybb.arrow -------------------------------------------------------------------------------- /js/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /target 3 | **/*.rs.bk 4 | bin/ 5 | pkg/ 6 | wasm-pack.log 7 | .pnp.cjs 8 | .pnp.loader.mjs 9 | docs_build/ 10 | .yarn 11 | -------------------------------------------------------------------------------- /js/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | # Note: we force node-modules so that tests can access node_modules/tape/bin/tape 2 | nodeLinker: node-modules 3 | -------------------------------------------------------------------------------- /js/DEVELOP.md: -------------------------------------------------------------------------------- 1 | 2 | ### 🛠️ Build with `wasm-pack build` 3 | 4 | ``` 5 | wasm-pack build 6 | ``` 7 | 8 | ### 🔬 Test in Headless Browsers with `wasm-pack test` 9 | 10 | ``` 11 | wasm-pack test --headless --firefox 12 | ``` 13 | 14 | ### 🎁 Publish to NPM with `wasm-pack publish` 15 | 16 | ``` 17 | wasm-pack publish 18 | ``` 19 | -------------------------------------------------------------------------------- /js/LICENSE_APACHE: -------------------------------------------------------------------------------- 1 | ../LICENSE_APACHE -------------------------------------------------------------------------------- /js/LICENSE_MIT: -------------------------------------------------------------------------------- 1 | ../LICENSE_MIT -------------------------------------------------------------------------------- /js/RELEASE.md: -------------------------------------------------------------------------------- 1 | ## Release docs 2 | 3 | ```bash 4 | export PATH="/opt/homebrew/opt/llvm/bin/:$PATH" 5 | export CC=/opt/homebrew/opt/llvm/bin/clang 6 | export AR=/opt/homebrew/opt/llvm/bin/llvm-ar 7 | ``` 8 | 9 | ``` 10 | yarn build 11 | cd pkg 12 | npm publish 13 | ``` 14 | 15 | ``` 16 | yarn build:geoparquet 17 | cd pkg 18 | npm publish 19 | ``` 20 | 21 | ``` 22 | yarn build:flatgeobuf 23 | cd pkg 24 | npm publish 25 | ``` 26 | -------------------------------------------------------------------------------- /js/build/modules/flatgeobuf-wasm/README.md: -------------------------------------------------------------------------------- 1 | # `@flatgeobuf-wasm` 2 | 3 | 4 | ## Publishing 5 | 6 | ```bash 7 | ./build.sh 8 | wasm-pack publish --access=public 9 | ``` 10 | -------------------------------------------------------------------------------- /js/build/modules/geoparquet-wasm/README.md: -------------------------------------------------------------------------------- 1 | # `@geoarrow/geoparquet-wasm` 2 | -------------------------------------------------------------------------------- /js/build/modules/geoparquet-wasm/build.sh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/js/build/modules/geoparquet-wasm/build.sh -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "build": "FEATURES='--all-features' NAME='@geoarrow/geoarrow-wasm' bash ./scripts/build.sh", 4 | "build:test": "ENV='DEV' FEATURES='--all-features' bash ./scripts/build.sh", 5 | "build:geoparquet": "FEATURES='--no-default-features --features debug --features io_parquet --features io_parquet_async --features io_parquet_compressions' NAME='@geoarrow/geoparquet-wasm' bash ./scripts/build.sh", 6 | "build:flatgeobuf": "FEATURES='--no-default-features --features debug --features io_flatgeobuf' NAME='@geoarrow/flatgeobuf-wasm' bash ./scripts/build.sh", 7 | "docs:build": "typedoc", 8 | "docs:serve": "cd docs_build && http-server", 9 | "docs:publish": "gh-pages --dist docs_build --dest js/", 10 | "test": "vitest run" 11 | }, 12 | "devDependencies": { 13 | "@swc/core": "^1.3.83", 14 | "@swc/helpers": "^0.5.2", 15 | "@types/node": "^20.4.0", 16 | "apache-arrow": "^15.0.1", 17 | "arrow-js-ffi": "^0.4.1", 18 | "gh-pages": "^5.0.0", 19 | "http-server": "^14.1.1", 20 | "typedoc": "0.24.8", 21 | "typescript": "^4.6.2", 22 | "vitest": "^0.34.0" 23 | }, 24 | "volta": { 25 | "node": "20.4.0", 26 | "yarn": "3.3.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/affine_ops.rs: -------------------------------------------------------------------------------- 1 | use crate::broadcasting::BroadcastableAffine; 2 | use crate::data::*; 3 | use geoarrow::algorithm::broadcasting::BroadcastableVec; 4 | use wasm_bindgen::prelude::*; 5 | 6 | macro_rules! impl_rotate { 7 | ($struct_name:ident) => { 8 | #[wasm_bindgen] 9 | impl $struct_name { 10 | /// Apply an affine transformation like `scale`, `skew`, or `rotate` to an array of 11 | /// geometries. 12 | #[wasm_bindgen(js_name = affineTransform)] 13 | pub fn affine_transform(&self, transform: BroadcastableAffine) -> Self { 14 | use geoarrow::algorithm::geo::AffineOps; 15 | match transform.0 { 16 | BroadcastableVec::Array(arr) => { 17 | AffineOps::affine_transform(&self.0, arr.as_slice()).into() 18 | } 19 | BroadcastableVec::Scalar(scalar) => { 20 | AffineOps::affine_transform(&self.0, &scalar).into() 21 | } 22 | } 23 | } 24 | } 25 | }; 26 | } 27 | 28 | impl_rotate!(PointData); 29 | impl_rotate!(LineStringData); 30 | impl_rotate!(PolygonData); 31 | impl_rotate!(MultiPointData); 32 | impl_rotate!(MultiLineStringData); 33 | impl_rotate!(MultiPolygonData); 34 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/contains.rs: -------------------------------------------------------------------------------- 1 | use crate::array::*; 2 | use wasm_bindgen::prelude::*; 3 | 4 | macro_rules! impl_contains { 5 | ($first:ty, $second:ty) => { 6 | #[wasm_bindgen] 7 | impl $first { 8 | /// Checks if `rhs` is completely contained within `self`. 9 | /// More formally, the interior of `rhs` has non-empty 10 | /// (set-theoretic) intersection but neither the interior, 11 | /// nor the boundary of `rhs` intersects the exterior of 12 | /// `self`. In other words, the [DE-9IM] intersection matrix 13 | /// of `(rhs, self)` is `T*F**F***`. 14 | /// 15 | /// [DE-9IM]: https://en.wikipedia.org/wiki/DE-9IM 16 | #[wasm_bindgen] 17 | pub fn contains(&self, other: &$second) -> BooleanData { 18 | use geoarrow::algorithm::geo::Contains; 19 | BooleanData(Contains::contains(&self.0, &other.0)) 20 | } 21 | } 22 | }; 23 | } 24 | 25 | // TODO: JS doesn't support function overloading 26 | // Implementations on PointData 27 | impl_contains!(PointArray, PointData); 28 | impl_contains!(PointArray, LineStringData); 29 | impl_contains!(PointArray, PolygonData); 30 | impl_contains!(PointArray, MultiPointData); 31 | impl_contains!(PointArray, MultiLineStringData); 32 | impl_contains!(PointArray, MultiPolygonData); 33 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/geodesic_length.rs: -------------------------------------------------------------------------------- 1 | use crate::data::*; 2 | use arrow_wasm::data::Data; 3 | use geoarrow::algorithm::geo::GeodesicLength; 4 | use wasm_bindgen::prelude::*; 5 | 6 | macro_rules! impl_geodesic_length { 7 | ($struct_name:ident) => { 8 | #[wasm_bindgen] 9 | impl $struct_name { 10 | /// Determine the length of a geometry on an ellipsoidal model of the earth. 11 | /// 12 | /// This uses the geodesic measurement methods given by [Karney (2013)]. As opposed to 13 | /// older methods like Vincenty, this method is accurate to a few nanometers and always 14 | /// converges. 15 | /// 16 | /// [Karney (2013)]: https://arxiv.org/pdf/1109.4448.pdf 17 | #[wasm_bindgen(js_name = geodesicLength)] 18 | pub fn geodesic_length(&self) -> Data { 19 | Data::from_array(GeodesicLength::geodesic_length(&self.0)) 20 | } 21 | } 22 | }; 23 | } 24 | 25 | impl_geodesic_length!(PointData); 26 | impl_geodesic_length!(MultiPointData); 27 | impl_geodesic_length!(LineStringData); 28 | impl_geodesic_length!(MultiLineStringData); 29 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/haversine_length.rs: -------------------------------------------------------------------------------- 1 | use crate::data::*; 2 | use arrow_wasm::data::Data; 3 | use geoarrow::algorithm::geo::HaversineLength; 4 | use wasm_bindgen::prelude::*; 5 | 6 | macro_rules! impl_haversine_length { 7 | ($struct_name:ident) => { 8 | #[wasm_bindgen] 9 | impl $struct_name { 10 | /// Determine the length of a geometry using the [haversine formula]. 11 | /// 12 | /// [haversine formula]: https://en.wikipedia.org/wiki/Haversine_formula 13 | /// 14 | /// *Note*: this implementation uses a mean earth radius of 6371.088 km, based on the 15 | /// [recommendation of the IUGG](ftp://athena.fsv.cvut.cz/ZFG/grs80-Moritz.pdf) 16 | #[wasm_bindgen(js_name = haversineLength)] 17 | pub fn haversine_length(&self) -> Data { 18 | Data::from_array(HaversineLength::haversine_length(&self.0)) 19 | } 20 | } 21 | }; 22 | } 23 | 24 | impl_haversine_length!(PointData); 25 | impl_haversine_length!(MultiPointData); 26 | impl_haversine_length!(LineStringData); 27 | impl_haversine_length!(MultiLineStringData); 28 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod affine_ops; 2 | pub mod area; 3 | pub mod bounding_rect; 4 | pub mod center; 5 | pub mod centroid; 6 | pub mod chaikin_smoothing; 7 | pub mod chamberlain_duquette_area; 8 | // pub mod contains; 9 | pub mod convex_hull; 10 | pub mod densify; 11 | pub mod dimensions; 12 | pub mod euclidean_length; 13 | pub mod geodesic_area; 14 | pub mod geodesic_length; 15 | pub mod haversine_length; 16 | // pub mod rotate; 17 | pub mod scale; 18 | pub mod simplify; 19 | pub mod simplify_vw; 20 | pub mod skew; 21 | pub mod translate; 22 | pub mod vincenty_length; 23 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/translate.rs: -------------------------------------------------------------------------------- 1 | use crate::broadcasting::BroadcastableFloat; 2 | use crate::data::*; 3 | use wasm_bindgen::prelude::*; 4 | 5 | macro_rules! impl_translate { 6 | ($struct_name:ident) => { 7 | #[wasm_bindgen] 8 | impl $struct_name { 9 | /// Translate a Geometry along its axes by the given offsets 10 | #[wasm_bindgen] 11 | pub fn translate( 12 | &self, 13 | x_offset: BroadcastableFloat, 14 | y_offset: BroadcastableFloat, 15 | ) -> Self { 16 | use geoarrow::algorithm::geo::Translate; 17 | Translate::translate(&self.0, &x_offset.0, &y_offset.0).into() 18 | } 19 | } 20 | }; 21 | } 22 | 23 | impl_translate!(PointData); 24 | impl_translate!(LineStringData); 25 | impl_translate!(PolygonData); 26 | impl_translate!(MultiPointData); 27 | impl_translate!(MultiLineStringData); 28 | impl_translate!(MultiPolygonData); 29 | -------------------------------------------------------------------------------- /js/src/algorithm/geo/vincenty_length.rs: -------------------------------------------------------------------------------- 1 | use crate::data::*; 2 | use crate::error::WasmResult; 3 | use arrow_wasm::data::Data; 4 | use geoarrow::algorithm::geo::VincentyLength; 5 | use wasm_bindgen::prelude::*; 6 | 7 | macro_rules! impl_vincenty_length { 8 | ($struct_name:ident) => { 9 | #[wasm_bindgen] 10 | impl $struct_name { 11 | /// Determine the length of a geometry using [Vincenty’s formulae]. 12 | /// 13 | /// [Vincenty’s formulae]: https://en.wikipedia.org/wiki/Vincenty%27s_formulae 14 | #[wasm_bindgen(js_name = vincentyLength)] 15 | pub fn vincenty_length(&self) -> WasmResult { 16 | Ok(Data::from_array(VincentyLength::vincenty_length(&self.0)?)) 17 | } 18 | } 19 | }; 20 | } 21 | 22 | impl_vincenty_length!(PointData); 23 | impl_vincenty_length!(MultiPointData); 24 | impl_vincenty_length!(LineStringData); 25 | impl_vincenty_length!(MultiLineStringData); 26 | -------------------------------------------------------------------------------- /js/src/algorithm/geoarrow/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod coord_format; 2 | -------------------------------------------------------------------------------- /js/src/algorithm/mod.rs: -------------------------------------------------------------------------------- 1 | // pub mod geo; 2 | // pub mod geoarrow; 3 | -------------------------------------------------------------------------------- /js/src/data/coord.rs: -------------------------------------------------------------------------------- 1 | use geoarrow_array::array::{CoordBuffer, InterleavedCoordBuffer, SeparatedCoordBuffer}; 2 | use geoarrow_schema::Dimension; 3 | use wasm_bindgen::prelude::*; 4 | 5 | use crate::dimension::JsDimension; 6 | 7 | /// An immutable buffer of coordinates in WebAssembly memory, that can be either interleaved or 8 | /// separated. 9 | #[wasm_bindgen] 10 | #[allow(dead_code)] 11 | pub struct JsCoordBuffer(CoordBuffer); 12 | 13 | #[wasm_bindgen] 14 | impl JsCoordBuffer { 15 | /// Create a new CoordBuffer from a `Float64Array` of interleaved XY coordinates 16 | #[wasm_bindgen(js_name = fromInterleaved)] 17 | pub fn from_interleaved(coords: Vec, dim: JsDimension) -> Self { 18 | Self(InterleavedCoordBuffer::new(coords.into(), dim.into()).into()) 19 | } 20 | 21 | /// Create a new CoordBuffer from two `Float64Array`s of X and Y 22 | #[wasm_bindgen(js_name = fromSeparated)] 23 | pub fn from_separated(x: Vec, y: Vec) -> Self { 24 | let cb = SeparatedCoordBuffer::from_vec(vec![x.into(), y.into()], Dimension::XY).unwrap(); 25 | Self(cb.into()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /js/src/data/mod.rs: -------------------------------------------------------------------------------- 1 | mod coord; 2 | 3 | pub use coord::JsCoordBuffer; 4 | -------------------------------------------------------------------------------- /js/src/data_type.rs: -------------------------------------------------------------------------------- 1 | use geoarrow_schema::GeoArrowType; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen(js_name = GeoArrowType)] 5 | pub struct JsGeoArrowType(GeoArrowType); 6 | 7 | impl JsGeoArrowType { 8 | pub fn new(geoarrow_type: GeoArrowType) -> Self { 9 | Self(geoarrow_type) 10 | } 11 | } 12 | 13 | impl From for GeoArrowType { 14 | fn from(value: JsGeoArrowType) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl From for JsGeoArrowType { 20 | fn from(value: GeoArrowType) -> Self { 21 | Self(value) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/dimension.rs: -------------------------------------------------------------------------------- 1 | use geoarrow_schema::Dimension; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen(js_name = Dimension)] 5 | pub enum JsDimension { 6 | XY, 7 | XYZ, 8 | XYM, 9 | XYZM, 10 | } 11 | 12 | impl From for Dimension { 13 | fn from(value: JsDimension) -> Self { 14 | match value { 15 | JsDimension::XY => Dimension::XY, 16 | JsDimension::XYZ => Dimension::XYZ, 17 | JsDimension::XYM => Dimension::XYM, 18 | JsDimension::XYZM => Dimension::XYZM, 19 | } 20 | } 21 | } 22 | 23 | impl From for JsDimension { 24 | fn from(value: Dimension) -> Self { 25 | match value { 26 | Dimension::XY => JsDimension::XY, 27 | Dimension::XYZ => JsDimension::XYZ, 28 | Dimension::XYM => JsDimension::XYM, 29 | Dimension::XYZM => JsDimension::XYZM, 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /js/src/error.rs: -------------------------------------------------------------------------------- 1 | // use arrow2::error::Error as ArrowError; 2 | use arrow_wasm::error::ArrowWasmError; 3 | use thiserror::Error; 4 | use wasm_bindgen::JsError; 5 | 6 | #[derive(Error, Debug)] 7 | pub enum GeoArrowWasmError { 8 | // #[error(transparent)] 9 | // ArrowError(Box), 10 | #[error(transparent)] 11 | ArrowWasmError(Box), 12 | 13 | #[cfg(feature = "io_object_store")] 14 | #[error(transparent)] 15 | ObjectStoreError(#[from] object_store::Error), 16 | 17 | #[cfg(feature = "io_parquet")] 18 | #[error(transparent)] 19 | ParquetError(#[from] parquet::errors::ParquetError), 20 | 21 | #[error("Internal error: `{0}`")] 22 | InternalError(String), 23 | } 24 | 25 | pub type Result = std::result::Result; 26 | pub type WasmResult = std::result::Result; 27 | -------------------------------------------------------------------------------- /js/src/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod to_ffi; 2 | -------------------------------------------------------------------------------- /js/src/ffi/to_ffi/mod.rs: -------------------------------------------------------------------------------- 1 | // #[cfg(feature = "data")] 2 | // pub mod data; 3 | // #[cfg(feature = "vector")] 4 | // pub mod vector; 5 | -------------------------------------------------------------------------------- /js/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | // #[cfg(feature = "io_flatgeobuf")] 2 | // pub mod flatgeobuf; 3 | // #[cfg(feature = "io_geojson")] 4 | // pub mod geojson; 5 | // #[cfg(feature = "io_object_store")] 6 | // pub mod object_store; 7 | // #[cfg(feature = "io_object_store")] 8 | // pub mod object_store_s3; 9 | // #[cfg(feature = "io_parquet")] 10 | // pub mod parquet; 11 | -------------------------------------------------------------------------------- /js/src/io/object_store_s3/mod.rs: -------------------------------------------------------------------------------- 1 | //! This is vendored from https://github.com/JanKaul/object_store_s3_wasm 2 | //! under the MIT license 3 | -------------------------------------------------------------------------------- /js/src/io/parquet/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "io_parquet_async")] 2 | pub mod r#async; 3 | #[cfg(feature = "io_parquet_async")] 4 | pub mod async_file_reader; 5 | pub mod options; 6 | pub mod sync; 7 | 8 | #[cfg(feature = "io_parquet_async")] 9 | pub use r#async::{ParquetDataset, ParquetFile}; 10 | pub use sync::read_geoparquet; 11 | -------------------------------------------------------------------------------- /js/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "algorithm")] 2 | pub mod algorithm; 3 | #[cfg(feature = "data")] 4 | pub mod data; 5 | pub mod data_type; 6 | pub mod dimension; 7 | pub mod error; 8 | pub mod ffi; 9 | pub mod io; 10 | // #[cfg(feature = "geodesy")] 11 | // pub mod reproject; 12 | // #[cfg(feature = "scalar")] 13 | // pub mod scalar; 14 | #[cfg(feature = "vector")] 15 | pub mod vector; 16 | // pub mod transform_origin; 17 | pub mod utils; 18 | 19 | // pub use transform_origin::TransformOrigin; 20 | -------------------------------------------------------------------------------- /js/src/reproject.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::algorithm::geodesy::Direction; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub enum ReprojectDirection { 6 | /// `Fwd`: Indicate that a two-way operator, function, or method, 7 | /// should run in the *forward* direction. 8 | Fwd, 9 | 10 | /// `Inv`: Indicate that a two-way operator, function, or method, 11 | /// should run in the *inverse* direction. 12 | Inv, 13 | } 14 | 15 | impl From for Direction { 16 | fn from(value: ReprojectDirection) -> Self { 17 | match value { 18 | ReprojectDirection::Fwd => Self::Fwd, 19 | ReprojectDirection::Inv => Self::Inv, 20 | } 21 | } 22 | } 23 | 24 | impl From for ReprojectDirection { 25 | fn from(value: Direction) -> Self { 26 | match value { 27 | Direction::Fwd => Self::Fwd, 28 | Direction::Inv => Self::Inv, 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /js/src/scalar/linestring.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::scalar::OwnedLineString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct LineString(pub(crate) OwnedLineString); 6 | 7 | impl<'a> From<&'a LineString> for geoarrow::scalar::LineString<'a> { 8 | fn from(value: &'a LineString) -> Self { 9 | (&value.0).into() 10 | } 11 | } 12 | 13 | impl From for geoarrow::scalar::OwnedLineString { 14 | fn from(value: LineString) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl<'a> From> for LineString { 20 | fn from(value: geoarrow::scalar::LineString<'a>) -> Self { 21 | LineString(value.into()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/scalar/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod linestring; 2 | pub mod multilinestring; 3 | pub mod multipoint; 4 | pub mod multipolygon; 5 | pub mod point; 6 | pub mod polygon; 7 | 8 | pub use linestring::LineString; 9 | pub use multilinestring::MultiLineString; 10 | pub use multipoint::MultiPoint; 11 | pub use multipolygon::MultiPolygon; 12 | pub use point::Point; 13 | pub use polygon::Polygon; 14 | -------------------------------------------------------------------------------- /js/src/scalar/multilinestring.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::scalar::OwnedMultiLineString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct MultiLineString(pub(crate) OwnedMultiLineString); 6 | 7 | impl<'a> From<&'a MultiLineString> for geoarrow::scalar::MultiLineString<'a> { 8 | fn from(value: &'a MultiLineString) -> Self { 9 | (&value.0).into() 10 | } 11 | } 12 | 13 | impl From for geoarrow::scalar::OwnedMultiLineString { 14 | fn from(value: MultiLineString) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl<'a> From> for MultiLineString { 20 | fn from(value: geoarrow::scalar::MultiLineString<'a>) -> Self { 21 | MultiLineString(value.into()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/scalar/multipoint.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::scalar::OwnedMultiPoint; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct MultiPoint(pub(crate) OwnedMultiPoint); 6 | 7 | impl<'a> From<&'a MultiPoint> for geoarrow::scalar::MultiPoint<'a> { 8 | fn from(value: &'a MultiPoint) -> Self { 9 | (&value.0).into() 10 | } 11 | } 12 | 13 | impl From for geoarrow::scalar::OwnedMultiPoint { 14 | fn from(value: MultiPoint) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl<'a> From> for MultiPoint { 20 | fn from(value: geoarrow::scalar::MultiPoint<'a>) -> Self { 21 | MultiPoint(value.into()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/scalar/multipolygon.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::scalar::OwnedMultiPolygon; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct MultiPolygon(pub(crate) OwnedMultiPolygon); 6 | 7 | impl<'a> From<&'a MultiPolygon> for geoarrow::scalar::MultiPolygon<'a> { 8 | fn from(value: &'a MultiPolygon) -> Self { 9 | (&value.0).into() 10 | } 11 | } 12 | 13 | impl From for geoarrow::scalar::OwnedMultiPolygon { 14 | fn from(value: MultiPolygon) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl<'a> From> for MultiPolygon { 20 | fn from(value: geoarrow::scalar::MultiPolygon<'a>) -> Self { 21 | MultiPolygon(value.into()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/scalar/point.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::scalar::OwnedPoint; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct Point(pub(crate) OwnedPoint); 6 | 7 | impl<'a> From<&'a Point> for geoarrow::scalar::Point<'a> { 8 | fn from(value: &'a Point) -> Self { 9 | (&value.0).into() 10 | } 11 | } 12 | 13 | impl From for geoarrow::scalar::OwnedPoint { 14 | fn from(value: Point) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl<'a> From> for Point { 20 | fn from(value: geoarrow::scalar::Point<'a>) -> Self { 21 | Point(value.into()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/scalar/polygon.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::scalar::OwnedPolygon; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct Polygon(pub(crate) OwnedPolygon); 6 | 7 | impl<'a> From<&'a Polygon> for geoarrow::scalar::Polygon<'a> { 8 | fn from(value: &'a Polygon) -> Self { 9 | (&value.0).into() 10 | } 11 | } 12 | 13 | impl From for geoarrow::scalar::OwnedPolygon { 14 | fn from(value: Polygon) -> Self { 15 | value.0 16 | } 17 | } 18 | 19 | impl<'a> From> for Polygon { 20 | fn from(value: geoarrow::scalar::Polygon<'a>) -> Self { 21 | Polygon(value.into()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /js/src/transform_origin.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | #[wasm_bindgen] 4 | pub struct TransformOrigin(pub(crate) geoarrow::algorithm::geo::TransformOrigin); 5 | 6 | #[wasm_bindgen] 7 | impl TransformOrigin { 8 | #[wasm_bindgen] 9 | pub fn centroid() -> Self { 10 | Self(geoarrow::algorithm::geo::TransformOrigin::Centroid) 11 | } 12 | 13 | #[wasm_bindgen] 14 | pub fn center() -> Self { 15 | Self(geoarrow::algorithm::geo::TransformOrigin::Center) 16 | } 17 | 18 | #[wasm_bindgen] 19 | pub fn point(x: f64, y: f64) -> Self { 20 | Self(geoarrow::algorithm::geo::TransformOrigin::Point( 21 | geo::Point::new(x, y), 22 | )) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /js/src/utils.rs: -------------------------------------------------------------------------------- 1 | use arrow_buffer::OffsetBuffer; 2 | #[cfg(feature = "console_error_panic_hook")] 3 | use wasm_bindgen::prelude::*; 4 | 5 | #[cfg(feature = "console_error_panic_hook")] 6 | #[wasm_bindgen] 7 | pub fn set_panic_hook() { 8 | // When the `console_error_panic_hook` feature is enabled, we can call the 9 | // `set_panic_hook` function at least once during initialization, and then 10 | // we will get better error messages if our code ever panics. 11 | // 12 | // For more details see 13 | // https://github.com/rustwasm/console_error_panic_hook#readme 14 | console_error_panic_hook::set_once(); 15 | } 16 | 17 | /// Convert vec to OffsetsBuffer 18 | pub fn vec_to_offsets(v: Vec) -> OffsetBuffer { 19 | unsafe { OffsetBuffer::new_unchecked(v.into()) } 20 | } 21 | 22 | // A macro to provide `println!(..)`-style syntax for `console.log` logging. 23 | #[cfg(target_arch = "wasm32")] 24 | #[macro_export] 25 | macro_rules! log { 26 | ( $( $t:tt )* ) => { 27 | web_sys::console::log_1(&format!( $( $t )* ).into()); 28 | } 29 | } 30 | 31 | #[cfg(not(target_arch = "wasm32"))] 32 | #[macro_export] 33 | macro_rules! log { 34 | ( $( $t:tt )* ) => { 35 | println!("LOG - {}", format!( $( $t )* )); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /js/src/vector.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use geoarrow_array::GeoArrowArray; 4 | use geoarrow_schema::GeoArrowType; 5 | use wasm_bindgen::prelude::*; 6 | 7 | /// An immutable vector (chunked array) of geometries stored in WebAssembly memory using GeoArrow's 8 | /// in-memory representation. 9 | #[wasm_bindgen(js_name = GeoArrowVector)] 10 | pub struct JsGeoArrowVector { 11 | _chunks: Vec>, 12 | _data_type: GeoArrowType, 13 | } 14 | -------------------------------------------------------------------------------- /js/tests/js/example.test.ts: -------------------------------------------------------------------------------- 1 | import * as geoarrow from "../../pkg/node"; 2 | import { parseField, parseVector } from "arrow-js-ffi"; 3 | import { it } from "vitest"; 4 | 5 | geoarrow.set_panic_hook(); 6 | 7 | const WASM_MEMORY = geoarrow.wasmMemory(); 8 | 9 | it("hello world", () => { 10 | // let xs = new Float64Array([1, 2, 3, 4]); 11 | // let ys = new Float64Array([5, 6, 7, 8]); 12 | // let separatedCoords = new geoarrow.SeparatedCoordBuffer(xs, ys); 13 | // let coords = geoarrow.CoordBuffer.fromSeparatedCoords(separatedCoords); 14 | // let pointArray = new geoarrow.PointData(coords); 15 | 16 | // let xOffset = new Float64Array([1, 2, 3, 4]); 17 | // let yOffset = new Float64Array([1, 2, 3, 4]); 18 | 19 | // let translatedPoints = pointArray.translate( 20 | // geoarrow.BroadcastableFloat.fromArray(xOffset), 21 | // geoarrow.BroadcastableFloat.fromArray(yOffset) 22 | // ); 23 | 24 | // let ffiArray = translatedPoints.toFFI(); 25 | // const field = parseField(WASM_MEMORY.buffer, ffiArray.field_addr()); 26 | // const vector = parseVector( 27 | // WASM_MEMORY.buffer, 28 | // ffiArray.array_addr(), 29 | // field.type 30 | // ); 31 | 32 | // console.log(field.metadata); 33 | // console.log(vector.getChildAt(0)?.toArray()); 34 | }); 35 | -------------------------------------------------------------------------------- /js/tests/js/flatgeobuf.test.ts: -------------------------------------------------------------------------------- 1 | // import * as geoarrow from "../../pkg/node"; 2 | // import { tableFromIPC } from "apache-arrow"; 3 | // import { readFileSync } from "fs"; 4 | import { it } from "vitest"; 5 | 6 | it("hello world", () => {}); 7 | 8 | // geoarrow.set_panic_hook(); 9 | 10 | // it("read FlatGeobuf", () => { 11 | // const path = "../fixtures/flatgeobuf/nz-building-outlines-small.fgb"; 12 | // const buffer = new Uint8Array(readFileSync(path)); 13 | // const wasmTable = geoarrow.readFlatGeobuf(buffer); 14 | // const arrowIPCBuffer = wasmTable.intoIPCStream(); 15 | // const arrowJsTable = tableFromIPC(arrowIPCBuffer); 16 | // const geometryIdx = arrowJsTable.schema.fields.findIndex( 17 | // (field) => field.name === "geometry" 18 | // ); 19 | // const geometryField = arrowJsTable.schema.fields[geometryIdx]; 20 | // const geometryFieldMetadata = geometryField.metadata; 21 | // console.log(geometryFieldMetadata); 22 | // expect(geometryFieldMetadata.get("ARROW:extension:name")).toStrictEqual( 23 | // "geoarrow.multipolygon" 24 | // ); 25 | // }); 26 | -------------------------------------------------------------------------------- /js/tests/js/geoparquet.test.ts: -------------------------------------------------------------------------------- 1 | // import * as geoarrow from "../../pkg/node"; 2 | // import { tableFromIPC } from "apache-arrow"; 3 | // import { readFileSync } from "fs"; 4 | // import { expect, it } from "vitest"; 5 | 6 | // geoarrow.set_panic_hook(); 7 | 8 | // it("read GeoParquet", () => { 9 | // const path = "../fixtures/geoparquet/nybb.parquet"; 10 | // const buffer = new Uint8Array(readFileSync(path)); 11 | // const wasmTable = geoarrow.readGeoParquet(buffer); 12 | // const arrowIPCBuffer = wasmTable.intoIPCStream(); 13 | // const arrowJsTable = tableFromIPC(arrowIPCBuffer); 14 | // const geometryIdx = arrowJsTable.schema.fields.findIndex( 15 | // (field) => field.name === "geometry" 16 | // ); 17 | // const geometryField = arrowJsTable.schema.fields[geometryIdx]; 18 | // const geometryFieldMetadata = geometryField.metadata; 19 | // expect(geometryFieldMetadata.get("ARROW:extension:name")).toStrictEqual( 20 | // "geoarrow.multipolygon" 21 | // ); 22 | // }); 23 | 24 | import { it } from "vitest"; 25 | 26 | it("hello world", () => {}); 27 | -------------------------------------------------------------------------------- /js/tests/web.rs: -------------------------------------------------------------------------------- 1 | //! Test suite for the Web and headless browsers. 2 | 3 | #![cfg(target_arch = "wasm32")] 4 | 5 | extern crate wasm_bindgen_test; 6 | use wasm_bindgen_test::*; 7 | 8 | wasm_bindgen_test_configure!(run_in_browser); 9 | 10 | #[wasm_bindgen_test] 11 | fn pass() { 12 | assert_eq!(1 + 1, 2); 13 | } 14 | -------------------------------------------------------------------------------- /js/tsconfig.docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["pkg/**/*.d.ts"] 3 | } 4 | -------------------------------------------------------------------------------- /js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node" 5 | }, 6 | "include": ["tests/**/*"], 7 | "exclude": ["node_modules"], 8 | "ts-node": { 9 | "swc": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /js/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "geoarrow", 3 | "cleanOutputDir": true, 4 | "darkHighlightTheme": "material-theme-ocean", 5 | "entryPoints": [ 6 | "pkg/node/index.d.ts", 7 | "pkg/bundler/index.d.ts", 8 | "pkg/esm/index.d.ts", 9 | ], 10 | "lightHighlightTheme": "material-theme-lighter", 11 | "tsconfig": "tsconfig.docs.json", 12 | "out": "docs_build", 13 | "excludePrivate": true, 14 | "excludeProtected": true, 15 | "excludeExternals": true, 16 | "includeVersion": true 17 | } 18 | -------------------------------------------------------------------------------- /python/.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | 3 | tmp*.py 4 | tmp*.ts 5 | tmp*.js 6 | *.zip 7 | site 8 | /target 9 | 10 | # Byte-compiled / optimized / DLL files 11 | __pycache__/ 12 | .pytest_cache/ 13 | *.py[cod] 14 | 15 | # C extensions 16 | *.so 17 | 18 | # Distribution / packaging 19 | .Python 20 | .venv/ 21 | env/ 22 | bin/ 23 | build/ 24 | develop-eggs/ 25 | dist/ 26 | eggs/ 27 | lib/ 28 | lib64/ 29 | parts/ 30 | sdist/ 31 | var/ 32 | include/ 33 | man/ 34 | venv/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | pip-selfcheck.json 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | 52 | # Translations 53 | *.mo 54 | 55 | # Mr Developer 56 | .mr.developer.cfg 57 | .project 58 | .pydevproject 59 | 60 | # Rope 61 | .ropeproject 62 | 63 | # Django stuff: 64 | *.log 65 | *.pot 66 | 67 | .DS_Store 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyCharm 73 | .idea/ 74 | 75 | # VSCode 76 | .vscode/ 77 | 78 | # Pyenv 79 | .python-version 80 | -------------------------------------------------------------------------------- /python/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["geoarrow-compute", "geoarrow-core", "geoarrow-io"] 3 | resolver = "2" 4 | 5 | [workspace.package] 6 | authors = ["Kyle Barron "] 7 | version = "0.4.0-beta.4" 8 | edition = "2024" 9 | homepage = "https://geoarrow.org/geoarrow-rs/" 10 | repository = "https://github.com/geoarrow/geoarrow-rs" 11 | license = "MIT OR Apache-2.0" 12 | keywords = ["python", "arrow", "geospatial"] 13 | categories = ["wasm", "science::geo"] 14 | rust-version = "1.85" 15 | 16 | [workspace.dependencies] 17 | arrow = "55" 18 | arrow-array = "55" 19 | arrow-buffer = "55" 20 | arrow-schema = "55" 21 | geo-traits = "0.3" 22 | geoarrow-array = { path = "../rust/geoarrow-array" } 23 | geoarrow-cast = { path = "../rust/geoarrow-cast" } 24 | geoarrow-flatgeobuf = { path = "../rust/geoarrow-flatgeobuf" } 25 | geoarrow-schema = { path = "../rust/geoarrow-schema" } 26 | geoparquet = { path = "../rust/geoparquet" } 27 | geozero = "0.14" 28 | indexmap = "2.5.0" 29 | numpy = "0.25" 30 | object_store = "0.12" 31 | parquet = "55" 32 | pyo3 = { version = "0.25", features = ["hashbrown", "serde", "anyhow"] } 33 | pyo3-arrow = "0.10.1" 34 | pyo3-geoarrow = { path = "../rust/pyo3-geoarrow" } 35 | serde_json = "1" 36 | thiserror = "1" 37 | -------------------------------------------------------------------------------- /python/docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ../CHANGELOG.md -------------------------------------------------------------------------------- /python/docs/DEVELOP.md: -------------------------------------------------------------------------------- 1 | ../DEVELOP.md -------------------------------------------------------------------------------- /python/docs/api/compute/enums.md: -------------------------------------------------------------------------------- 1 | # Enums 2 | 3 | ::: geoarrow.rust.compute.enums 4 | -------------------------------------------------------------------------------- /python/docs/api/compute/functions.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | ## Array/Chunked Array functions 4 | 5 | ::: geoarrow.rust.compute 6 | options: 7 | filters: 8 | - "!^_" 9 | members: 10 | - affine_transform 11 | - area 12 | - center 13 | - centroid 14 | - chaikin_smoothing 15 | - convex_hull 16 | - densify 17 | - envelope 18 | - frechet_distance 19 | - geodesic_perimeter 20 | - is_empty 21 | - length 22 | - line_interpolate_point 23 | - line_locate_point 24 | - polylabel 25 | - rotate 26 | - scale 27 | - signed_area 28 | - simplify 29 | - skew 30 | - total_bounds 31 | - translate 32 | 33 | ## Table functions 34 | 35 | ::: geoarrow.rust.compute 36 | options: 37 | filters: 38 | - "!^_" 39 | members: 40 | - explode 41 | -------------------------------------------------------------------------------- /python/docs/api/compute/types.md: -------------------------------------------------------------------------------- 1 | # Types 2 | 3 | ::: geoarrow.rust.compute.types 4 | -------------------------------------------------------------------------------- /python/docs/api/core/array.md: -------------------------------------------------------------------------------- 1 | # Array 2 | 3 | ::: geoarrow.rust.core.GeoArrowArray 4 | options: 5 | show_if_no_docstring: true 6 | -------------------------------------------------------------------------------- /python/docs/api/core/chunked_array.md: -------------------------------------------------------------------------------- 1 | # Chunked Array 2 | 3 | ::: geoarrow.rust.core.ChunkedGeoArrowArray 4 | options: 5 | show_if_no_docstring: true 6 | -------------------------------------------------------------------------------- /python/docs/api/core/constructors.md: -------------------------------------------------------------------------------- 1 | # Constructors 2 | 3 | ::: geoarrow.rust.core 4 | options: 5 | filters: 6 | - "!^_" 7 | members: 8 | - CoordsInput 9 | - points 10 | - linestrings 11 | - polygons 12 | - multipoints 13 | - multilinestrings 14 | - multipolygons 15 | -------------------------------------------------------------------------------- /python/docs/api/core/enums.md: -------------------------------------------------------------------------------- 1 | # Enums 2 | 3 | ::: geoarrow.rust.core.enums 4 | -------------------------------------------------------------------------------- /python/docs/api/core/functions.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | Interoperability with other Python geospatial libraries (Shapely, GeoPandas) and in-memory geospatial formats (WKB, WKT). 4 | 5 | ::: geoarrow.rust.core 6 | options: 7 | filters: 8 | - "!^_" 9 | members: 10 | - read_pyogrio 11 | - from_geopandas 12 | - from_shapely 13 | - from_wkb 14 | - from_wkt 15 | - to_geopandas 16 | - to_shapely 17 | - to_wkb 18 | - to_wkt 19 | 20 | ## Table functions 21 | 22 | ::: geoarrow.rust.core 23 | options: 24 | filters: 25 | - "!^_" 26 | members: 27 | - geometry_col 28 | 29 | ## CRS Access 30 | 31 | ::: geoarrow.rust.core.get_crs 32 | -------------------------------------------------------------------------------- /python/docs/api/core/geometry/scalar.md: -------------------------------------------------------------------------------- 1 | # Geometry 2 | 3 | ::: geoarrow.rust.core 4 | options: 5 | filters: 6 | - "!^_" 7 | - "^__arrow" 8 | - "^__geo" 9 | members: 10 | - GeoArrowScalar 11 | -------------------------------------------------------------------------------- /python/docs/api/core/geometry/type.md: -------------------------------------------------------------------------------- 1 | # Type 2 | 3 | ::: geoarrow.rust.core.GeoArrowType 4 | -------------------------------------------------------------------------------- /python/docs/api/core/geometry_type.md: -------------------------------------------------------------------------------- 1 | # Geometry Type 2 | 3 | ::: geoarrow.rust.core.GeoArrowType 4 | ::: geoarrow.rust.core.point 5 | ::: geoarrow.rust.core.linestring 6 | ::: geoarrow.rust.core.polygon 7 | ::: geoarrow.rust.core.multipoint 8 | ::: geoarrow.rust.core.multilinestring 9 | ::: geoarrow.rust.core.multipolygon 10 | ::: geoarrow.rust.core.geometry 11 | ::: geoarrow.rust.core.geometrycollection 12 | ::: geoarrow.rust.core.box 13 | ::: geoarrow.rust.core.wkb 14 | ::: geoarrow.rust.core.large_wkb 15 | ::: geoarrow.rust.core.wkb_view 16 | ::: geoarrow.rust.core.wkt 17 | ::: geoarrow.rust.core.large_wkt 18 | ::: geoarrow.rust.core.wkt_view 19 | -------------------------------------------------------------------------------- /python/docs/api/core/index.md: -------------------------------------------------------------------------------- 1 | # `geoarrow.rust.core` 2 | 3 | Root for `geoarrow.rust.core` API docs. 4 | 5 | All functionality described within this directory are part of the `geoarrow.rust.core` submodule. To use, install the `geoarrow-rust-core` PyPI package: 6 | 7 | ``` 8 | pip install geoarrow-rust-core 9 | ``` 10 | -------------------------------------------------------------------------------- /python/docs/api/core/types.md: -------------------------------------------------------------------------------- 1 | # Types 2 | 3 | ::: geoarrow.rust.core.types 4 | -------------------------------------------------------------------------------- /python/docs/api/io/arrow_ipc.md: -------------------------------------------------------------------------------- 1 | # Arrow IPC 2 | 3 | It's possible to read and write GeoArrow data to the [Arrow IPC format](https://arrow.apache.org/docs/python/ipc.html). 4 | 5 | The Arrow IPC format is able to fully represent GeoArrow data. Loading such files back into memory will identically reproduce the prior data. 6 | 7 | Arrow IPC generically supports GeoArrow data without any extra behavior, so the functionality to read and write Arrow IPC files lives in [`arro3`](https://github.com/kylebarron/arro3). 8 | 9 | Refer to: 10 | 11 | - [`arro3.io.read_ipc`][] 12 | - [`arro3.io.read_ipc_stream`][] 13 | - [`arro3.io.write_ipc`][] 14 | - [`arro3.io.write_ipc_stream`][] 15 | 16 | When saved without any internal compression, the Arrow IPC format can also be memory-mapped, enabling faster reading. 17 | -------------------------------------------------------------------------------- /python/docs/api/io/csv.md: -------------------------------------------------------------------------------- 1 | # CSV 2 | 3 | Read and write CSV files with a geometry column encoded as Well-Known Text. 4 | 5 | ::: geoarrow.rust.io.read_csv 6 | ::: geoarrow.rust.io.write_csv 7 | -------------------------------------------------------------------------------- /python/docs/api/io/flatgeobuf.md: -------------------------------------------------------------------------------- 1 | # FlatGeobuf 2 | 3 | Read and write [FlatGeobuf](https://flatgeobuf.org/) files. 4 | 5 | ::: geoarrow.rust.io.read_flatgeobuf 6 | ::: geoarrow.rust.io.read_flatgeobuf_async 7 | ::: geoarrow.rust.io.write_flatgeobuf 8 | -------------------------------------------------------------------------------- /python/docs/api/io/gdal.md: -------------------------------------------------------------------------------- 1 | # GDAL 2 | 3 | GDAL natively supports reading data from any vector driver as GeoArrow data, and natively supports writing data to any vector driver from GeoArrow data. 4 | 5 | For reading and writing you have two options: 6 | 7 | - You can use [`pyogrio`'s Arrow integration](https://pyogrio.readthedocs.io/en/latest/api.html#arrow-integration) directly 8 | - You can use the [`geoarrow.rust.core.read_pyogrio`][] wrapper. 9 | 10 | This calls `pyogrio` under the hood (and requires that `pyogrio` is installed). The wrapper lives in `geoarrow.rust.core` because it has no dependency on any Rust IO code. 11 | -------------------------------------------------------------------------------- /python/docs/api/io/geojson.md: -------------------------------------------------------------------------------- 1 | # GeoJSON 2 | 3 | Read and write GeoJSON and newline-delimited GeoJSON files. 4 | 5 | ::: geoarrow.rust.io.read_geojson 6 | ::: geoarrow.rust.io.read_geojson_lines 7 | ::: geoarrow.rust.io.write_geojson 8 | ::: geoarrow.rust.io.write_geojson_lines 9 | -------------------------------------------------------------------------------- /python/docs/api/io/geoparquet.md: -------------------------------------------------------------------------------- 1 | # GeoParquet 2 | 3 | Read and write [GeoParquet](https://geoparquet.org/) files. 4 | 5 | ::: geoarrow.rust.io.read_parquet 6 | ::: geoarrow.rust.io.read_parquet_async 7 | ::: geoarrow.rust.io.write_parquet 8 | ::: geoarrow.rust.io.GeoParquetDataset 9 | ::: geoarrow.rust.io.GeoParquetFile 10 | ::: geoarrow.rust.io.GeoParquetWriter 11 | ::: geoarrow.rust.io.enums.GeoParquetEncoding 12 | ::: geoarrow.rust.io.types.GeoParquetEncodingT 13 | -------------------------------------------------------------------------------- /python/docs/api/io/postgis.md: -------------------------------------------------------------------------------- 1 | # PostGIS 2 | 3 | Read from a PostGIS database. 4 | 5 | ::: geoarrow.rust.io.read_postgis 6 | ::: geoarrow.rust.io.read_postgis_async 7 | -------------------------------------------------------------------------------- /python/docs/api/io/shapefile.md: -------------------------------------------------------------------------------- 1 | # Shapefile 2 | 3 | Read Shapefile files. 4 | 5 | ::: geoarrow.rust.io.read_shapefile 6 | -------------------------------------------------------------------------------- /python/docs/ecosystem/geopandas.md: -------------------------------------------------------------------------------- 1 | # GeoPandas 2 | 3 | Use the [`from_geopandas`][geoarrow.rust.core.from_geopandas] and [`to_geopandas`][geoarrow.rust.core.to_geopandas] functions to convert to and from GeoPandas. 4 | 5 | ```py 6 | import geopandas as gpd 7 | from geoarrow.rust.core import from_geopandas, to_geopandas 8 | 9 | gdf = gpd.GeoDataFrame(...) 10 | table = from_geopandas(gdf) 11 | back_to_geopandas_gdf = to_geopandas(table) 12 | ``` 13 | -------------------------------------------------------------------------------- /python/docs/ecosystem/lonboard.md: -------------------------------------------------------------------------------- 1 | # Lonboard 2 | 3 | [Lonboard][lonboard_docs] is a Python library for fast, interactive geospatial vector data visualization in Jupyter. 4 | 5 | [![](https://raw.githubusercontent.com/developmentseed/lonboard/main/assets/hero-image.jpg)][lonboard_docs] 6 | 7 | Lonboard was designed from the ground up to be used with GeoArrow and is the reason why Lonboard is fast. 8 | 9 | As of Lonboard version 0.6 or later, just pass a GeoTable as the `table` parameter of a layer. 10 | 11 | ## Examples 12 | 13 | ```py 14 | from geoarrow.rust.core import read_geojson 15 | from lonboard import Map, PathLayer 16 | 17 | path = "/path/to/file.geojson" 18 | geo_table = read_geojson(path) 19 | geo_table.geometry 20 | 21 | layer = PathLayer(table=geo_table) 22 | m = Map(layer) 23 | m 24 | ``` 25 | 26 | Refer to [lonboard's documentation][lonboard_docs] for more examples. 27 | 28 | [lonboard_docs]: https://developmentseed.org/lonboard/latest/ 29 | -------------------------------------------------------------------------------- /python/docs/ecosystem/pyogrio.md: -------------------------------------------------------------------------------- 1 | # Pyogrio/GDAL 2 | 3 | Use the [`read_pyogrio`][geoarrow.rust.core.read_pyogrio] function to read an OGR-supported data source through [pyogrio](https://pyogrio.readthedocs.io/en/latest/). 4 | 5 | This requires the optional `pyogrio` and `pyarrow` dependencies. 6 | 7 | ```py 8 | from geoarrow.rust.core import read_pyogrio, geometry_col 9 | 10 | path = "path/to/file.shp" 11 | table = read_pyogrio(path) 12 | geometry = geometry_col(table) 13 | ``` 14 | -------------------------------------------------------------------------------- /python/docs/ecosystem/shapely.md: -------------------------------------------------------------------------------- 1 | # Shapely 2 | 3 | For interoperability with [Shapely](https://shapely.readthedocs.io/en/stable/index.html), use the top-level [`to_shapely`][geoarrow.rust.core.to_shapely] and [`from_shapely`][geoarrow.rust.core.from_shapely] functions. 4 | 5 | Shapely interoperability requires `shapely` to be installed, and requires Shapely version 2.0 or higher. 6 | 7 | ## Examples 8 | 9 | ```py 10 | from geoarrow.rust.core import from_shapely, to_shapely 11 | import shapely 12 | 13 | shapely_geoms = to_shapely(geoarrow_array) 14 | geoarrow_array = from_shapely(shapely_geoms) 15 | ``` 16 | -------------------------------------------------------------------------------- /python/docs/index.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /python/docs/stylesheets/extra.css: -------------------------------------------------------------------------------- 1 | [data-md-color-scheme="rust-light"] { 2 | --md-primary-fg-color: #dea584; 3 | --md-primary-bg-color: #1f292d; 4 | --md-primary-fg-color--light: #f9c6a9; 5 | --md-primary-fg-color--dark: #c28a6a; 6 | } 7 | 8 | /* Override just a couple colors from slate */ 9 | [data-md-color-scheme="slate"] { 10 | --md-primary-fg-color: #dea584; 11 | --md-primary-bg-color: #1f292d; 12 | --md-primary-fg-color--light: #f9c6a9; 13 | --md-primary-fg-color--dark: #c28a6a; 14 | } 15 | -------------------------------------------------------------------------------- /python/geoarrow-compute/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-rust-compute" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | description = "Efficient, vectorized geospatial operations in Python." 7 | readme = "README.md" 8 | repository = { workspace = true } 9 | homepage = { workspace = true } 10 | license = { workspace = true } 11 | keywords = { workspace = true } 12 | categories = { workspace = true } 13 | rust-version = { workspace = true } 14 | 15 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 16 | [lib] 17 | name = "_compute" 18 | crate-type = ["cdylib"] 19 | 20 | [dependencies] 21 | arrow = { workspace = true } 22 | arrow-array = { workspace = true } 23 | arrow-buffer = { workspace = true } 24 | pyo3 = { workspace = true } 25 | pyo3-arrow = { workspace = true } 26 | pyo3-geoarrow = { workspace = true } 27 | geo = "0.30" 28 | numpy = { workspace = true } 29 | -------------------------------------------------------------------------------- /python/geoarrow-compute/README.md: -------------------------------------------------------------------------------- 1 | # `geoarrow.rust.compute` 2 | 3 | Compute operations on GeoArrow data. 4 | 5 | ## Documentation 6 | 7 | Refer to the documentation at [geoarrow.org/geoarrow-rs/python](https://geoarrow.org/geoarrow-rs/python). 8 | -------------------------------------------------------------------------------- /python/geoarrow-compute/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.4.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "geoarrow-rust-compute" 7 | requires-python = ">=3.9" 8 | dependencies = ["arro3-core>=0.4", "geoarrow-rust-core", "pyproj"] 9 | classifiers = [ 10 | "Programming Language :: Rust", 11 | "Programming Language :: Python :: Implementation :: CPython", 12 | "Programming Language :: Python :: Implementation :: PyPy", 13 | ] 14 | dynamic = ["version"] 15 | 16 | [tool.maturin] 17 | features = ["pyo3/extension-module"] 18 | module-name = "geoarrow.rust.compute._compute" 19 | python-source = "python" 20 | -------------------------------------------------------------------------------- /python/geoarrow-compute/python/geoarrow/rust/compute/__init__.py: -------------------------------------------------------------------------------- 1 | from . import enums 2 | from ._compute import * 3 | from ._compute import ___version 4 | 5 | __version__: str = ___version() 6 | -------------------------------------------------------------------------------- /python/geoarrow-compute/python/geoarrow/rust/compute/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/geoarrow-compute/python/geoarrow/rust/compute/py.typed -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/center.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 5 | use geoarrow::algorithm::geo::Center; 6 | use pyo3::prelude::*; 7 | use pyo3_geoarrow::PyGeoArrowResult; 8 | 9 | #[pyfunction] 10 | pub fn center(py: Python, input: AnyNativeInput) -> PyGeoArrowResult { 11 | match input { 12 | AnyNativeInput::Array(arr) => { 13 | let out = arr.as_ref().center()?; 14 | return_geometry_array(py, Arc::new(out)) 15 | } 16 | AnyNativeInput::Chunked(arr) => { 17 | let out = arr.as_ref().center()?; 18 | return_chunked_geometry_array(py, Arc::new(out)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/centroid.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 5 | use geoarrow::algorithm::geo::Centroid; 6 | use pyo3::prelude::*; 7 | use pyo3_geoarrow::PyGeoArrowResult; 8 | 9 | #[pyfunction] 10 | pub fn centroid(py: Python, input: AnyNativeInput) -> PyGeoArrowResult { 11 | match input { 12 | AnyNativeInput::Array(arr) => { 13 | let out = arr.as_ref().centroid()?; 14 | return_geometry_array(py, Arc::new(out)) 15 | } 16 | AnyNativeInput::Chunked(arr) => { 17 | let out = arr.as_ref().centroid()?; 18 | return_chunked_geometry_array(py, Arc::new(out)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/chaikin_smoothing.rs: -------------------------------------------------------------------------------- 1 | use crate::ffi::from_python::AnyNativeInput; 2 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 3 | use geoarrow::algorithm::geo::ChaikinSmoothing; 4 | use pyo3::prelude::*; 5 | use pyo3_geoarrow::PyGeoArrowResult; 6 | 7 | #[pyfunction] 8 | pub fn chaikin_smoothing( 9 | py: Python, 10 | input: AnyNativeInput, 11 | n_iterations: u32, 12 | ) -> PyGeoArrowResult { 13 | match input { 14 | AnyNativeInput::Array(arr) => { 15 | let out = arr.as_ref().chaikin_smoothing(n_iterations)?; 16 | return_geometry_array(py, out) 17 | } 18 | AnyNativeInput::Chunked(arr) => { 19 | let out = arr.as_ref().chaikin_smoothing(n_iterations)?; 20 | return_chunked_geometry_array(py, out) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/convex_hull.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 5 | use geoarrow::algorithm::geo::ConvexHull; 6 | use geoarrow::array::PolygonArray; 7 | use geoarrow::chunked_array::ChunkedGeometryArray; 8 | use pyo3::prelude::*; 9 | use pyo3_geoarrow::PyGeoArrowResult; 10 | 11 | #[pyfunction] 12 | pub fn convex_hull(py: Python, input: AnyNativeInput) -> PyGeoArrowResult { 13 | match input { 14 | AnyNativeInput::Array(arr) => { 15 | let out: PolygonArray = arr.as_ref().convex_hull()?; 16 | return_geometry_array(py, Arc::new(out)) 17 | } 18 | AnyNativeInput::Chunked(arr) => { 19 | let out: ChunkedGeometryArray = arr.as_ref().convex_hull()?; 20 | return_chunked_geometry_array(py, Arc::new(out)) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/densify.rs: -------------------------------------------------------------------------------- 1 | use crate::ffi::from_python::AnyNativeInput; 2 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 3 | use geoarrow::algorithm::geo::Densify; 4 | use pyo3::prelude::*; 5 | use pyo3_geoarrow::PyGeoArrowResult; 6 | 7 | #[pyfunction] 8 | pub fn densify(py: Python, input: AnyNativeInput, max_distance: f64) -> PyGeoArrowResult { 9 | match input { 10 | AnyNativeInput::Array(arr) => { 11 | let out = arr.as_ref().densify(max_distance)?; 12 | return_geometry_array(py, out) 13 | } 14 | AnyNativeInput::Chunked(arr) => { 15 | let out = arr.as_ref().densify(max_distance)?; 16 | return_chunked_geometry_array(py, out) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/dimensions.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use crate::util::{return_array, return_chunked_array}; 5 | use geoarrow::algorithm::geo::HasDimensions; 6 | use pyo3::prelude::*; 7 | use pyo3_arrow::{PyArray, PyChunkedArray}; 8 | use pyo3_geoarrow::PyGeoArrowResult; 9 | 10 | #[pyfunction] 11 | pub fn is_empty(py: Python, input: AnyNativeInput) -> PyGeoArrowResult { 12 | match input { 13 | AnyNativeInput::Array(arr) => { 14 | let out = HasDimensions::is_empty(&arr.as_ref())?; 15 | return_array(py, PyArray::from_array_ref(Arc::new(out))) 16 | } 17 | AnyNativeInput::Chunked(arr) => { 18 | let out = HasDimensions::is_empty(&arr.as_ref())?; 19 | return_chunked_array(py, PyChunkedArray::from_array_refs(out.chunk_refs())?) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/envelope.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 5 | use geoarrow::algorithm::geo::BoundingRect; 6 | use pyo3::prelude::*; 7 | use pyo3_geoarrow::PyGeoArrowResult; 8 | 9 | #[pyfunction] 10 | pub fn envelope(py: Python, input: AnyNativeInput) -> PyGeoArrowResult { 11 | match input { 12 | AnyNativeInput::Array(arr) => { 13 | let out = arr.as_ref().bounding_rect()?; 14 | return_geometry_array(py, Arc::new(out)) 15 | } 16 | AnyNativeInput::Chunked(arr) => { 17 | let out = arr.as_ref().bounding_rect()?; 18 | return_chunked_geometry_array(py, Arc::new(out)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/geodesic_area.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use crate::util::{return_array, return_chunked_array}; 5 | use geoarrow::algorithm::geo::GeodesicArea; 6 | use pyo3::prelude::*; 7 | use pyo3_arrow::{PyArray, PyChunkedArray}; 8 | use pyo3_geoarrow::PyGeoArrowResult; 9 | 10 | #[pyfunction] 11 | pub fn geodesic_perimeter(py: Python, input: AnyNativeInput) -> PyGeoArrowResult { 12 | match input { 13 | AnyNativeInput::Array(arr) => { 14 | let out = arr.as_ref().geodesic_perimeter()?; 15 | return_array(py, PyArray::from_array_ref(Arc::new(out))) 16 | } 17 | AnyNativeInput::Chunked(arr) => { 18 | let out = arr.as_ref().geodesic_perimeter()?; 19 | return_chunked_array(py, PyChunkedArray::from_array_refs(out.chunk_refs())?) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod affine_ops; 2 | pub(crate) mod area; 3 | pub(crate) mod center; 4 | pub(crate) mod centroid; 5 | pub(crate) mod chaikin_smoothing; 6 | pub(crate) mod convex_hull; 7 | pub(crate) mod densify; 8 | pub(crate) mod dimensions; 9 | pub(crate) mod envelope; 10 | pub(crate) mod frechet_distance; 11 | pub(crate) mod geodesic_area; 12 | pub(crate) mod length; 13 | pub(crate) mod line_interpolate_point; 14 | pub(crate) mod line_locate_point; 15 | pub(crate) mod rotate; 16 | pub(crate) mod scale; 17 | pub(crate) mod simplify; 18 | pub(crate) mod skew; 19 | pub(crate) mod translate; 20 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/geo/skew.rs: -------------------------------------------------------------------------------- 1 | use crate::ffi::from_python::AnyNativeInput; 2 | use crate::util::{return_chunked_geometry_array, return_geometry_array}; 3 | use geoarrow::algorithm::geo::Skew; 4 | use geoarrow::chunked_array::ChunkedNativeArrayDyn; 5 | use geoarrow::error::GeoArrowError; 6 | use pyo3::prelude::*; 7 | use pyo3_geoarrow::PyGeoArrowResult; 8 | 9 | #[pyfunction] 10 | #[pyo3(signature = (geom, xs=0.0, ys=0.0))] 11 | pub fn skew(py: Python, geom: AnyNativeInput, xs: f64, ys: f64) -> PyGeoArrowResult { 12 | match geom { 13 | AnyNativeInput::Array(arr) => { 14 | let out = arr.as_ref().skew_xy(&xs.into(), &ys.into())?; 15 | return_geometry_array(py, out) 16 | } 17 | AnyNativeInput::Chunked(chunked) => { 18 | let out = chunked 19 | .as_ref() 20 | .geometry_chunks() 21 | .iter() 22 | .map(|chunk| chunk.as_ref().skew_xy(&xs.into(), &ys.into())) 23 | .collect::, GeoArrowError>>()?; 24 | let out_refs = out.iter().map(|x| x.as_ref()).collect::>(); 25 | return_chunked_geometry_array( 26 | py, 27 | ChunkedNativeArrayDyn::from_geoarrow_chunks(out_refs.as_slice())?.into_inner(), 28 | ) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod geo; 2 | pub mod native; 3 | 4 | #[cfg(feature = "libc")] 5 | pub mod polylabel; 6 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/native/explode.rs: -------------------------------------------------------------------------------- 1 | use geoarrow::algorithm::native::ExplodeTable; 2 | use pyo3::prelude::*; 3 | use pyo3_arrow::PyTable; 4 | use pyo3_arrow::export::Arro3Table; 5 | use pyo3_geoarrow::PyGeoArrowResult; 6 | 7 | use crate::util::{pytable_to_table, table_to_pytable}; 8 | 9 | #[pyfunction] 10 | pub fn explode(py: Python, input: PyTable) -> PyGeoArrowResult { 11 | let table = pytable_to_table(input)?; 12 | let exploded_table = py.allow_threads(|| table.explode(None))?; 13 | Ok(table_to_pytable(exploded_table).into()) 14 | } 15 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/native/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod explode; 2 | pub mod total_bounds; 3 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/native/total_bounds.rs: -------------------------------------------------------------------------------- 1 | use crate::ffi::from_python::AnyNativeInput; 2 | use geoarrow::algorithm::native::TotalBounds; 3 | use pyo3::prelude::*; 4 | use pyo3_geoarrow::PyGeoArrowResult; 5 | 6 | #[pyfunction] 7 | pub fn total_bounds(input: AnyNativeInput) -> PyGeoArrowResult<(f64, f64, f64, f64)> { 8 | match input { 9 | AnyNativeInput::Array(arr) => Ok(arr.as_ref().total_bounds().into()), 10 | AnyNativeInput::Chunked(arr) => Ok(arr.as_ref().total_bounds().into()), 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/algorithm/polylabel.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use crate::ffi::from_python::AnyNativeInput; 4 | use geoarrow::algorithm::polylabel::Polylabel; 5 | use geoarrow::array::NativeArrayDyn; 6 | use pyo3::prelude::*; 7 | use pyo3_geoarrow::PyGeoArrowResult; 8 | use pyo3_geoarrow::{PyChunkedNativeArray, PyNativeArray}; 9 | 10 | #[pyfunction] 11 | pub fn polylabel(py: Python, input: AnyNativeInput, tolerance: f64) -> PyGeoArrowResult { 12 | match input { 13 | AnyNativeInput::Array(arr) => { 14 | let out = arr.as_ref().polylabel(tolerance)?; 15 | Ok(PyNativeArray::new(NativeArrayDyn::new(Arc::new(out))) 16 | .into_pyobject(py)? 17 | .into_any() 18 | .unbind()) 19 | } 20 | AnyNativeInput::Chunked(chunked) => { 21 | let out = chunked.as_ref().polylabel(tolerance)?; 22 | Ok(PyChunkedNativeArray::new(Arc::new(out)) 23 | .into_pyobject(py)? 24 | .into_any() 25 | .unbind()) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/ffi/from_python/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod input; 2 | 3 | pub use input::AnyNativeInput; 4 | -------------------------------------------------------------------------------- /python/geoarrow-compute/src/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | //! Arrow FFI via the C Data Interface and the Arrow PyCapsule Interface. 2 | 3 | pub mod from_python; 4 | -------------------------------------------------------------------------------- /python/geoarrow-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-rust-core" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | description = "Efficient, vectorized geospatial operations in Python." 7 | readme = "README.md" 8 | repository = { workspace = true } 9 | homepage = { workspace = true } 10 | license = { workspace = true } 11 | keywords = { workspace = true } 12 | categories = { workspace = true } 13 | rust-version = { workspace = true } 14 | 15 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 16 | [lib] 17 | name = "_rust" 18 | crate-type = ["cdylib"] 19 | 20 | [features] 21 | 22 | [dependencies] 23 | pyo3 = { workspace = true } 24 | pyo3-geoarrow = { workspace = true, features = ["geozero"] } 25 | geoarrow-array = { workspace = true } 26 | geoarrow-schema = { workspace = true } 27 | -------------------------------------------------------------------------------- /python/geoarrow-core/DEVELOP.md: -------------------------------------------------------------------------------- 1 | ## Pyodide 2 | 3 | 4 | Install rust nightly and add wasm toolchain 5 | 6 | ``` 7 | rustup toolchain install nightly 8 | rustup target add --toolchain nightly wasm32-unknown-emscripten 9 | ``` 10 | 11 | Install dependencies. You need to set the `pyodide-build` version to the same version as the `pyodide` release you distribute for. 12 | 13 | ``` 14 | pip install -U maturin 15 | pip install pyodide-build 16 | ``` 17 | 18 | Install emsdk. 19 | 20 | ``` 21 | git clone https://github.com/emscripten-core/emsdk.git 22 | cd emsdk 23 | PYODIDE_EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version) 24 | ./emsdk install ${PYODIDE_EMSCRIPTEN_VERSION} 25 | ./emsdk activate ${PYODIDE_EMSCRIPTEN_VERSION} 26 | source emsdk_env.sh 27 | cd .. 28 | ``` 29 | 30 | - You must use `--no-default-features` to remove any async support. `tokio` does not compile for emscripten. 31 | 32 | ```bash 33 | maturin build / 34 | --no-default-features / 35 | --release / 36 | -o dist / 37 | --target wasm32-unknown-emscripten 38 | ``` 39 | -------------------------------------------------------------------------------- /python/geoarrow-core/README.md: -------------------------------------------------------------------------------- 1 | # `geoarrow.rust.core` 2 | 3 | Core data structures to store and manage geometry data in GeoArrow format. 4 | 5 | ## Documentation 6 | 7 | Refer to the [documentation website](https://geoarrow.org/geoarrow-rs/python). 8 | 9 | ## Documentation 10 | 11 | Refer to the documentation at [geoarrow.org/geoarrow-rs/python](https://geoarrow.org/geoarrow-rs/python). 12 | -------------------------------------------------------------------------------- /python/geoarrow-core/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.4.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "geoarrow-rust-core" 7 | requires-python = ">=3.9" 8 | dependencies = ["arro3-core>=0.4", "pyproj"] 9 | classifiers = [ 10 | "Programming Language :: Rust", 11 | "Programming Language :: Python :: Implementation :: CPython", 12 | "Programming Language :: Python :: Implementation :: PyPy", 13 | ] 14 | dynamic = ["version"] 15 | 16 | [tool.maturin] 17 | features = ["pyo3/extension-module"] 18 | module-name = "geoarrow.rust.core._rust" 19 | python-source = "python" 20 | -------------------------------------------------------------------------------- /python/geoarrow-core/python/geoarrow/rust/core/__init__.py: -------------------------------------------------------------------------------- 1 | from . import enums 2 | from ._crs import get_crs 3 | from ._rust import * 4 | from ._rust import ___version 5 | 6 | __version__: str = ___version() 7 | -------------------------------------------------------------------------------- /python/geoarrow-core/python/geoarrow/rust/core/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/geoarrow-core/python/geoarrow/rust/core/py.typed -------------------------------------------------------------------------------- /python/geoarrow-core/python/geoarrow/rust/core/types.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Literal, Union 4 | from .enums import CoordType, Dimension, Edges 5 | 6 | # The top-level import doesn't work for docs interlinking 7 | from pyproj.crs.crs import CRS 8 | 9 | CRSInput = Union[CRS, str, dict, int] 10 | """Acceptable input for the CRS parameter. 11 | 12 | This can be a `pyproj.CRS` object or anything that can be passed to 13 | `pyproj.CRS.from_user_input()`. 14 | """ 15 | 16 | IntFloat = Union[int, float] 17 | 18 | 19 | CoordTypeT = Literal["interleaved", "separated"] 20 | """Acceptable coord_type strings. 21 | """ 22 | 23 | DimensionT = Literal["XY", "XYZ", "XYM", "XYZM", "xy", "xyz", "xym", "xyzm"] 24 | """Acceptable dimension strings. 25 | """ 26 | 27 | EdgesT = Literal["andoyer", "karney", "spherical", "thomas", "vincenty"] 28 | """Acceptable edges strings. 29 | """ 30 | 31 | 32 | CoordTypeInput = Union[CoordType, CoordTypeT] 33 | """Acceptable coord_type input. 34 | """ 35 | 36 | DimensionInput = Union[Dimension, DimensionT] 37 | """Acceptable dimension input. 38 | """ 39 | 40 | EdgesInput = Union[Edges, EdgesT] 41 | """Acceptable edges input. 42 | """ 43 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/ffi/from_python/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod input; 2 | 3 | pub use input::AnyNativeInput; 4 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | //! Arrow FFI via the C Data Interface and the Arrow PyCapsule Interface. 2 | 3 | pub mod from_python; 4 | pub mod to_python; 5 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/ffi/to_python/array.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use geoarrow::NativeArray; 4 | use geoarrow::array::NativeArrayDyn; 5 | use geoarrow::chunked_array::ChunkedNativeArray; 6 | use pyo3::prelude::*; 7 | use pyo3_geoarrow::{PyChunkedNativeArray, PyNativeArray}; 8 | 9 | use pyo3_geoarrow::PyGeoArrowResult; 10 | 11 | pub fn native_array_to_pyobject( 12 | py: Python, 13 | arr: Arc, 14 | ) -> PyGeoArrowResult { 15 | Ok(PyNativeArray::new(NativeArrayDyn::new(arr)) 16 | .into_pyobject(py)? 17 | .into_any() 18 | .unbind()) 19 | } 20 | 21 | pub fn chunked_native_array_to_pyobject( 22 | py: Python, 23 | arr: Arc, 24 | ) -> PyGeoArrowResult { 25 | Ok(PyChunkedNativeArray::new(arr) 26 | .into_pyobject(py)? 27 | .into_any() 28 | .unbind()) 29 | } 30 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/ffi/to_python/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod array; 2 | 3 | pub use array::{chunked_native_array_to_pyobject, native_array_to_pyobject}; 4 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/geopandas/from_geopandas.rs: -------------------------------------------------------------------------------- 1 | use crate::interop::util::import_geopandas; 2 | use pyo3::PyAny; 3 | use pyo3::exceptions::PyValueError; 4 | use pyo3::intern; 5 | use pyo3::prelude::*; 6 | use pyo3::types::{PyDict, PyTuple}; 7 | use pyo3_arrow::PyTable; 8 | use pyo3_arrow::export::Arro3Table; 9 | use pyo3_geoarrow::PyGeoArrowResult; 10 | 11 | #[pyfunction] 12 | pub fn from_geopandas(py: Python, input: &Bound) -> PyGeoArrowResult { 13 | let geopandas_mod = import_geopandas(py)?; 14 | let geodataframe_class = geopandas_mod.getattr(intern!(py, "GeoDataFrame"))?; 15 | if !input.is_instance(&geodataframe_class)? { 16 | return Err(PyValueError::new_err("Expected GeoDataFrame input.").into()); 17 | } 18 | 19 | // Note: I got an error in test_write_native_multi_points in `from_geopandas` with the WKB 20 | // encoding 21 | let kwargs = PyDict::new(py); 22 | kwargs.set_item("geometry_encoding", "geoarrow")?; 23 | let table = input 24 | .call_method( 25 | intern!(py, "to_arrow"), 26 | PyTuple::new(py, std::iter::empty::())?, 27 | Some(&kwargs), 28 | )? 29 | .extract::()?; 30 | 31 | Ok(table.into()) 32 | } 33 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/geopandas/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod from_geopandas; 2 | pub mod to_geopandas; 3 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/geopandas/to_geopandas.rs: -------------------------------------------------------------------------------- 1 | use crate::interop::util::import_geopandas; 2 | use pyo3::intern; 3 | use pyo3::prelude::*; 4 | use pyo3::types::PyTuple; 5 | use pyo3_geoarrow::PyGeoArrowResult; 6 | 7 | #[pyfunction] 8 | pub fn to_geopandas(py: Python, input: PyObject) -> PyGeoArrowResult { 9 | let geopandas_mod = import_geopandas(py)?; 10 | let geodataframe_class = geopandas_mod.getattr(intern!(py, "GeoDataFrame"))?; 11 | let gdf = geodataframe_class 12 | .call_method1(intern!(py, "from_arrow"), PyTuple::new(py, vec![input])?)?; 13 | Ok(gdf.into()) 14 | } 15 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod geopandas; 2 | pub mod numpy; 3 | pub mod pyogrio; 4 | pub mod shapely; 5 | pub mod util; 6 | pub mod wkb; 7 | pub mod wkt; 8 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/numpy/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod to_numpy; 2 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/pyogrio/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod from_pyogrio; 2 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/shapely/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod from_shapely; 2 | pub mod to_shapely; 3 | pub mod utils; 4 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/interop/shapely/utils.rs: -------------------------------------------------------------------------------- 1 | use pyo3::exceptions::PyValueError; 2 | use pyo3::intern; 3 | use pyo3::prelude::*; 4 | use pyo3_geoarrow::PyGeoArrowResult; 5 | 6 | pub(crate) fn import_shapely(py: Python) -> PyGeoArrowResult> { 7 | let shapely_mod = py.import(intern!(py, "shapely"))?; 8 | let shapely_version_string = shapely_mod 9 | .getattr(intern!(py, "__version__"))? 10 | .extract::()?; 11 | if !shapely_version_string.starts_with('2') { 12 | Err(PyValueError::new_err("Shapely version 2 required").into()) 13 | } else { 14 | Ok(shapely_mod) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /python/geoarrow-core/src/table/geo_interface.rs: -------------------------------------------------------------------------------- 1 | // use pyo3_geoarrow::PyGeoArrowResult; 2 | // use geoarrow::error::GeoArrowError; 3 | // use geozero::ProcessToJson; 4 | // use pyo3::intern; 5 | // use pyo3::prelude::*; 6 | 7 | // #[pymethods] 8 | // impl GeoTable { 9 | // /// Implements the "geo interface protocol". 10 | // /// 11 | // /// See 12 | // #[getter] 13 | // pub fn __geo_interface__<'a>(&'a self, py: Python<'a>) -> PyGeoArrowResult> { 14 | // let mut table = self.0.clone(); 15 | // let json_string = table.to_json().map_err(GeoArrowError::GeozeroError)?; 16 | // let json_mod = py.import(intern!(py, "json"))?; 17 | // let args = (json_string.into_py(py),); 18 | // Ok(json_mod.call_method1(intern!(py, "loads"), args)?) 19 | // } 20 | // } 21 | -------------------------------------------------------------------------------- /python/geoarrow-io/README.md: -------------------------------------------------------------------------------- 1 | # `geoarrow.rust.io` 2 | 3 | Read and write geospatial file formats to and from GeoArrow. 4 | 5 | ## Documentation 6 | 7 | Refer to the documentation at [geoarrow.org/geoarrow-rs/python](https://geoarrow.org/geoarrow-rs/python). 8 | -------------------------------------------------------------------------------- /python/geoarrow-io/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.4.0,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "geoarrow-rust-io" 7 | requires-python = ">=3.9" 8 | dependencies = ["arro3-core>=0.4", "pyproj"] 9 | classifiers = [ 10 | "Programming Language :: Rust", 11 | "Programming Language :: Python :: Implementation :: CPython", 12 | "Programming Language :: Python :: Implementation :: PyPy", 13 | ] 14 | dynamic = ["version"] 15 | 16 | [tool.maturin] 17 | features = ["pyo3/extension-module"] 18 | module-name = "geoarrow.rust.io._io" 19 | python-source = "python" 20 | -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/__init__.py: -------------------------------------------------------------------------------- 1 | from . import enums 2 | from ._io import * 3 | from ._io import ___version 4 | 5 | __version__: str = ___version() 6 | -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/_io.pyi: -------------------------------------------------------------------------------- 1 | from ._csv import read_csv as read_csv 2 | from ._csv import write_csv as write_csv 3 | from ._flatgeobuf import read_flatgeobuf as read_flatgeobuf 4 | from ._flatgeobuf import read_flatgeobuf_async as read_flatgeobuf_async 5 | from ._flatgeobuf import write_flatgeobuf as write_flatgeobuf 6 | from ._geojson import read_geojson as read_geojson 7 | from ._geojson import read_geojson_lines as read_geojson_lines 8 | from ._geojson import write_geojson as write_geojson 9 | from ._geojson import write_geojson_lines as write_geojson_lines 10 | from ._parquet import GeoParquetDataset as GeoParquetDataset 11 | from ._parquet import GeoParquetFile as GeoParquetFile 12 | from ._parquet import GeoParquetWriter as GeoParquetWriter 13 | from ._parquet import read_parquet as read_parquet 14 | from ._parquet import read_parquet_async as read_parquet_async 15 | from ._parquet import write_parquet as write_parquet 16 | from ._postgis import read_postgis as read_postgis 17 | from ._postgis import read_postgis_async as read_postgis_async 18 | from ._shapefile import read_shapefile as read_shapefile 19 | -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/_postgis.pyi: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Optional 4 | 5 | from arro3.core import Table 6 | 7 | def read_postgis(connection_url: str, sql: str) -> Optional[Table]: 8 | """ 9 | Read a PostGIS query into an Arrow Table. 10 | 11 | Args: 12 | connection_url: _description_ 13 | sql: _description_ 14 | 15 | Returns: 16 | Table from query. 17 | """ 18 | 19 | async def read_postgis_async(connection_url: str, sql: str) -> Optional[Table]: 20 | """ 21 | Read a PostGIS query into an Arrow Table. 22 | 23 | Args: 24 | connection_url: _description_ 25 | sql: _description_ 26 | 27 | Returns: 28 | Table from query. 29 | """ 30 | -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/_shapefile.pyi: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from pathlib import Path 4 | from typing import Union 5 | 6 | from arro3.core import Table 7 | from geoarrow.rust.core.enums import CoordType 8 | from geoarrow.rust.core.types import CoordTypeT 9 | 10 | def read_shapefile( 11 | shp_path: Union[str, Path], 12 | *, 13 | batch_size: int = 65536, 14 | coord_type: CoordType | CoordTypeT | None = None, 15 | ) -> Table: 16 | """ 17 | Read a Shapefile into an Arrow Table. 18 | 19 | The returned Arrow table will have geometry information in native GeoArrow encoding. 20 | 21 | Args: 22 | shp_path: the path to the `.shp` file 23 | 24 | Other args: 25 | batch_size: the number of rows to include in each internal batch of the table. 26 | coord_type: The coordinate type. Defaults to None. 27 | 28 | """ 29 | -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/enums.py: -------------------------------------------------------------------------------- 1 | from enum import Enum, auto 2 | 3 | 4 | class StrEnum(str, Enum): 5 | def __new__(cls, value, *args, **kwargs): 6 | if not isinstance(value, (str, auto)): 7 | raise TypeError( 8 | f"Values of StrEnums must be strings: {value!r} is a {type(value)}" 9 | ) 10 | return super().__new__(cls, value, *args, **kwargs) 11 | 12 | def __str__(self): 13 | return str(self.value) 14 | 15 | def _generate_next_value_(name, *_): 16 | return name.lower() 17 | 18 | 19 | class GeoParquetEncoding(StrEnum): 20 | """Options for geometry encoding in GeoParquet.""" 21 | 22 | WKB = auto() 23 | """Use Well-Known Binary (WKB) encoding when writing GeoParquet files. 24 | """ 25 | 26 | Native = auto() 27 | """Use native GeoArrow geometry types when writing GeoParquet files. 28 | 29 | Supported as of GeoParquet version 1.1. 30 | 31 | This option provides for better read and write performance and for inferring spatial 32 | partitioning from remote files. But it does not yet have widespread support. 33 | """ 34 | -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/geoarrow-io/python/geoarrow/rust/io/py.typed -------------------------------------------------------------------------------- /python/geoarrow-io/python/geoarrow/rust/io/types.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Literal 4 | 5 | 6 | GeoParquetEncodingT = Literal["wkb", "native"] 7 | """Acceptable strings to be passed into the `encoding` parameter for 8 | [`write_parquet`][geoarrow.rust.io.write_parquet]. 9 | """ 10 | -------------------------------------------------------------------------------- /python/geoarrow-io/src/io/flatgeobuf/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "async")] 2 | mod r#async; 3 | mod sync; 4 | 5 | #[cfg(feature = "async")] 6 | pub use r#async::read_flatgeobuf_async; 7 | pub use sync::{read_flatgeobuf, write_flatgeobuf}; 8 | -------------------------------------------------------------------------------- /python/geoarrow-io/src/io/geojson.rs: -------------------------------------------------------------------------------- 1 | use crate::error::PyGeoArrowResult; 2 | use crate::io::input::sync::{FileReader, FileWriter}; 3 | use crate::util::to_arro3_table; 4 | 5 | use geoarrow::io::geojson::read_geojson as _read_geojson; 6 | use geoarrow::io::geojson::write_geojson as _write_geojson; 7 | use pyo3::prelude::*; 8 | use pyo3_arrow::PyRecordBatchReader; 9 | use pyo3_arrow::export::Arro3Table; 10 | 11 | #[pyfunction] 12 | #[pyo3(signature = (file, *, batch_size=65536))] 13 | pub fn read_geojson(mut file: FileReader, batch_size: usize) -> PyGeoArrowResult { 14 | let table = _read_geojson(&mut file, Some(batch_size))?; 15 | Ok(to_arro3_table(table)) 16 | } 17 | 18 | #[pyfunction] 19 | pub fn write_geojson(table: PyRecordBatchReader, file: FileWriter) -> PyGeoArrowResult<()> { 20 | _write_geojson(table.into_reader()?, file)?; 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /python/geoarrow-io/src/io/geojson_lines.rs: -------------------------------------------------------------------------------- 1 | use crate::error::PyGeoArrowResult; 2 | use crate::io::input::sync::{FileReader, FileWriter}; 3 | use crate::util::to_arro3_table; 4 | 5 | use geoarrow::io::geojson_lines::read_geojson_lines as _read_geojson_lines; 6 | use geoarrow::io::geojson_lines::write_geojson_lines as _write_geojson_lines; 7 | use pyo3::prelude::*; 8 | use pyo3_arrow::export::Arro3Table; 9 | use pyo3_arrow::input::AnyRecordBatch; 10 | 11 | #[pyfunction] 12 | #[pyo3(signature = (file, *, batch_size=65536))] 13 | pub fn read_geojson_lines(mut file: FileReader, batch_size: usize) -> PyGeoArrowResult { 14 | let table = _read_geojson_lines(&mut file, Some(batch_size))?; 15 | Ok(to_arro3_table(table)) 16 | } 17 | 18 | #[pyfunction] 19 | pub fn write_geojson_lines(table: AnyRecordBatch, file: FileWriter) -> PyGeoArrowResult<()> { 20 | _write_geojson_lines(table.into_reader()?, file)?; 21 | Ok(()) 22 | } 23 | -------------------------------------------------------------------------------- /python/geoarrow-io/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read and write to geospatial file formats. 2 | 3 | pub mod csv; 4 | pub mod flatgeobuf; 5 | pub mod geojson; 6 | pub mod geojson_lines; 7 | pub mod input; 8 | pub mod parquet; 9 | #[cfg(feature = "async")] 10 | pub mod postgis; 11 | pub mod shapefile; 12 | -------------------------------------------------------------------------------- /python/geoarrow-io/src/parquet/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "async")] 2 | mod r#async; 3 | mod sync; 4 | 5 | pub mod options; 6 | 7 | #[cfg(feature = "async")] 8 | pub use r#async::{GeoParquetDataset, GeoParquetFile, read_parquet_async}; 9 | pub use sync::{PyGeoParquetWriter, read_parquet, write_parquet}; 10 | -------------------------------------------------------------------------------- /python/geoarrow-io/src/runtime.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use pyo3::exceptions::PyValueError; 4 | use pyo3::prelude::*; 5 | use pyo3::sync::GILOnceCell; 6 | use tokio::runtime::Runtime; 7 | 8 | static RUNTIME: GILOnceCell> = GILOnceCell::new(); 9 | 10 | /// Get the tokio runtime for sync requests 11 | pub(crate) fn get_runtime(py: Python<'_>) -> PyResult> { 12 | let runtime = RUNTIME.get_or_try_init(py, || { 13 | Ok::<_, PyErr>(Arc::new(Runtime::new().map_err(|err| { 14 | PyValueError::new_err(format!("Could not create tokio runtime. {}", err)) 15 | })?)) 16 | })?; 17 | Ok(runtime.clone()) 18 | } 19 | -------------------------------------------------------------------------------- /python/metapackage/DEVELOP.md: -------------------------------------------------------------------------------- 1 | ## Publishing 2 | 3 | Install dependencies: 4 | 5 | ``` 6 | pip install -U build twine 7 | ``` 8 | 9 | then build the package: 10 | 11 | ``` 12 | python -m build 13 | ``` 14 | 15 | then upload to pypi: 16 | 17 | ``` 18 | python -m twine upload dist/* 19 | ``` 20 | -------------------------------------------------------------------------------- /python/metapackage/README.md: -------------------------------------------------------------------------------- 1 | # `geoarrow-rust` 2 | 3 | This is a metapackage for the `geoarrow.rust` namespace. 4 | 5 | Both the `geoarrow` and `geoarrow-rust` Python libraries are distributed with [namespace packaging](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/), meaning that each python package `geoarrow-[submodule-name]` and `geoarrow-rust-[submodule-name]` (imported as `geoarrow.[submodule-name]` or `geoarrow.rust.[submodule-name]`) can be published to PyPI independently. 6 | 7 | In order to obtain relevant modules, you should install them from PyPI directly, e.g.: 8 | 9 | ``` 10 | pip install geoarrow-rust-core 11 | ``` 12 | -------------------------------------------------------------------------------- /python/metapackage/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling"] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "geoarrow-rust" 7 | version = "0.1.0" 8 | description = 'Metapackage for geoarrow.rust namespace.' 9 | readme = "README.md" 10 | requires-python = ">=3.7" 11 | license = "Apache-2.0" 12 | keywords = [] 13 | authors = [{ name = "Kyle Barron", email = "kylebarron2@gmail.com" }] 14 | classifiers = [ 15 | "Programming Language :: Python", 16 | "Programming Language :: Python :: 3.9", 17 | "Programming Language :: Python :: 3.10", 18 | "Programming Language :: Python :: 3.11", 19 | "Programming Language :: Python :: 3.12", 20 | ] 21 | dependencies = ["geoarrow-rust-core"] 22 | 23 | [project.urls] 24 | Documentation = "https://geoarrow.org" 25 | Issues = "https://github.com/geoarrow/geoarrow-rs/issues" 26 | Source = "https://github.com/geoarrow/geoarrow-rs" 27 | -------------------------------------------------------------------------------- /python/proj/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-rust-proj" 3 | version = "0.1.0" 4 | authors = ["Kyle Barron "] 5 | edition = "2024" 6 | description = "GeoArrow bindings to PROJ." 7 | readme = "README.md" 8 | repository = "https://github.com/geoarrow/geoarrow-rs" 9 | license = "MIT OR Apache-2.0" 10 | keywords = ["python", "arrow", "geospatial"] 11 | categories = ["wasm", "science::geo"] 12 | rust-version = "1.85" 13 | 14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 15 | [lib] 16 | name = "_rust_proj" 17 | crate-type = ["cdylib"] 18 | 19 | [dependencies] 20 | arrow-array = "50" 21 | arrow-buffer = "50" 22 | arrow = { version = "50", features = ["ffi"] } 23 | pyo3 = { version = "0.24", features = [ 24 | "abi3-py38", 25 | "multiple-pymethods", 26 | "hashbrown", 27 | "serde", 28 | "anyhow", 29 | ] } 30 | geo = "0.30" 31 | geoarrow-rust-core = { path = "../core" } 32 | -------------------------------------------------------------------------------- /python/proj/README.md: -------------------------------------------------------------------------------- 1 | # `geoarrow.rust.proj` 2 | 3 | Python bindings to [PROJ](https://proj.org/en/9.3/) for coordinate reprojection on GeoArrow arrays. 4 | -------------------------------------------------------------------------------- /python/proj/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.2.1,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "geoarrow-rust-proj" 7 | requires-python = ">=3.9" 8 | dependencies = [] 9 | classifiers = [ 10 | "Programming Language :: Rust", 11 | "Programming Language :: Python :: Implementation :: CPython", 12 | "Programming Language :: Python :: Implementation :: PyPy", 13 | ] 14 | dynamic = ["version"] 15 | 16 | [tool.maturin] 17 | features = ["pyo3/extension-module"] 18 | module-name = "geoarrow.rust.proj._rust_proj" 19 | python-source = "python" 20 | -------------------------------------------------------------------------------- /python/proj/python/geoarrow/rust/proj/__init__.py: -------------------------------------------------------------------------------- 1 | from ._rust_proj import * 2 | -------------------------------------------------------------------------------- /python/proj/python/geoarrow/rust/proj/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/proj/python/geoarrow/rust/proj/py.typed -------------------------------------------------------------------------------- /python/proj/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | 3 | const VERSION: &str = env!("CARGO_PKG_VERSION"); 4 | 5 | #[pyfunction] 6 | fn ___version() -> &'static str { 7 | VERSION 8 | } 9 | 10 | /// A Python module implemented in Rust. 11 | #[pymodule] 12 | fn _rust_proj(_py: Python, m: &PyModule) -> PyResult<()> { 13 | m.add_wrapped(wrap_pyfunction!(___version))?; 14 | 15 | Ok(()) 16 | } 17 | -------------------------------------------------------------------------------- /python/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "python" 3 | version = "0.1.0" 4 | requires-python = ">=3.9" 5 | dependencies = [] 6 | 7 | [tool.uv] 8 | dev-dependencies = [ 9 | "affine>=2.4.0", 10 | "arro3-core>=0.5.0", 11 | "black>=24.10.0", 12 | "geodatasets>=2024.8.0", 13 | "geopandas>=1.0.1", 14 | "griffe-inherited-docstrings>=1.0.1", 15 | "ipykernel>=6.29.5", 16 | "maturin>=1.7.4", 17 | "mkdocs>=1.6.1", 18 | "mkdocs-material[imaging]>=9.5.40", 19 | "pip>=24.2", 20 | "pyarrow>=17.0.0", 21 | "pyogrio>=0.10.0", 22 | "pytest>=8.3.3", 23 | "shapely>=2.0.6", 24 | "mkdocstrings[python]>=0.29.1", 25 | "mike>=2.1.3", 26 | "numpy", 27 | "obstore>=0.6.0", 28 | "lonboard>=0.10.4", 29 | "geoarrow-types>=0.3.0", 30 | ] 31 | -------------------------------------------------------------------------------- /python/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests/__init__.py -------------------------------------------------------------------------------- /python/tests/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests/core/__init__.py -------------------------------------------------------------------------------- /python/tests/core/test_array.py: -------------------------------------------------------------------------------- 1 | import geodatasets 2 | import geopandas as gpd 3 | import pyarrow as pa 4 | import shapely 5 | from geoarrow.rust.core import GeoArrowArray 6 | from geoarrow.types.type_pyarrow import registered_extension_types 7 | 8 | 9 | def test_eq(): 10 | geoms = shapely.points([1, 2, 3], [4, 5, 6]) 11 | arr = GeoArrowArray.from_arrow(gpd.GeoSeries(geoms).to_arrow("geoarrow")) 12 | assert arr == arr 13 | 14 | with registered_extension_types(): 15 | pa_arr = pa.array(arr) 16 | assert arr == pa_arr 17 | assert arr == GeoArrowArray.from_arrow(pa_arr) 18 | 19 | 20 | def test_getitem(): 21 | # Tests both the __getitem__ method and the scalar geo interface in round trip 22 | # conversion to shapely. 23 | gdf = gpd.read_file(geodatasets.get_path("ny.bb")) 24 | arr = GeoArrowArray.from_arrow(gdf.geometry.to_arrow("geoarrow")) 25 | for i in range(len(arr)): 26 | assert shapely.geometry.shape(arr[i]).equals(gdf.geometry.iloc[i]) # type: ignore 27 | -------------------------------------------------------------------------------- /python/tests/core/test_scalar.py: -------------------------------------------------------------------------------- 1 | import geopandas as gpd 2 | import pyarrow as pa 3 | import shapely 4 | from arro3.core import Scalar 5 | from geoarrow.rust.core import GeoArrowArray, point 6 | from geoarrow.types.type_pyarrow import registered_extension_types 7 | 8 | 9 | def test_eq(): 10 | geoms = shapely.points([1, 2, 3], [4, 5, 6]) 11 | arr = GeoArrowArray.from_arrow(gpd.GeoSeries(geoms).to_arrow("geoarrow")) 12 | assert arr[0] == arr[0] 13 | 14 | # pyarrow doesn't implement __arrow_c_array__ on scalars 15 | with registered_extension_types(): 16 | pa_arr = pa.array(arr) 17 | assert arr[0] == GeoArrowArray.from_arrow(pa_arr)[0] 18 | 19 | # test with arro3 20 | assert arr[0] == Scalar.from_arrow(arr[0]) 21 | assert arr[0] == GeoArrowArray.from_arrow(Scalar.from_arrow(arr[0]))[0] 22 | 23 | 24 | def test_type(): 25 | geoms = shapely.points([1, 2, 3], [4, 5, 6]) 26 | arr = GeoArrowArray.from_arrow(gpd.GeoSeries(geoms).to_arrow("geoarrow")) 27 | assert arr[0].type == point("xy", coord_type="interleaved") 28 | -------------------------------------------------------------------------------- /python/tests/io/test_flatgeobuf.py: -------------------------------------------------------------------------------- 1 | from tempfile import TemporaryDirectory 2 | 3 | import pyogrio 4 | from geoarrow.rust.io import write_flatgeobuf 5 | 6 | from tests.utils import FIXTURES_DIR 7 | 8 | 9 | def test_write_flatgeobuf_with_wkb_geometry(): 10 | path = FIXTURES_DIR / "flatgeobuf" / "countries.fgb" 11 | # pyogrio.read_arrow leaves the geometry as WKB when reading. 12 | (meta, table) = pyogrio.read_arrow(path) 13 | 14 | field_meta = table.schema.field("wkb_geometry").metadata 15 | assert field_meta[b"ARROW:extension:name"] == b"geoarrow.wkb" 16 | 17 | with TemporaryDirectory() as tmpdir: 18 | tmp_path = f"{tmpdir}/countries.fgb" 19 | write_flatgeobuf(table, tmp_path, write_index=False) 20 | 21 | (meta2, table2) = pyogrio.read_arrow(path) 22 | 23 | assert table == table2 24 | -------------------------------------------------------------------------------- /python/tests/utils.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | 4 | def get_repo_root() -> Path: 5 | current_dir = Path(".").absolute() 6 | 7 | while current_dir.stem != "geoarrow-rs": 8 | if current_dir == Path("/"): 9 | raise ValueError("Could not find repo root; is it named geoarrow-rs?") 10 | current_dir = current_dir.parent 11 | 12 | return current_dir 13 | 14 | 15 | REPO_ROOT = get_repo_root() 16 | FIXTURES_DIR = REPO_ROOT / "fixtures" 17 | 18 | -------------------------------------------------------------------------------- /python/tests_old/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests_old/__init__.py -------------------------------------------------------------------------------- /python/tests_old/algorithm/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests_old/algorithm/__init__.py -------------------------------------------------------------------------------- /python/tests_old/algorithm/test_affine_ops.py: -------------------------------------------------------------------------------- 1 | import geoarrow.rust.compute as grc 2 | import geoarrow.rust.core as gars 3 | import geodatasets 4 | import geopandas as gpd 5 | import shapely.geometry 6 | from affine import Affine 7 | 8 | nybb_path = geodatasets.get_path("nybb") 9 | 10 | 11 | def test_affine_function(): 12 | gdf = gpd.read_file(nybb_path) 13 | # shapely_area = gdf.geometry.area 14 | assert isinstance(gdf, gpd.GeoDataFrame) 15 | 16 | table = gars.from_geopandas(gdf) 17 | geom = gars.geometry_col(table) 18 | 19 | xoff = 10 20 | yoff = 20 21 | 22 | affine = Affine.translation(xoff, yoff) 23 | translated = grc.affine_transform(geom, affine) 24 | orig_geom = geom.chunk(0)[0] 25 | translated_geom = translated.chunk(0)[0] 26 | 27 | first_coord = shapely.geometry.shape(orig_geom).geoms[0].exterior.coords[0] 28 | first_coord_translated = ( 29 | shapely.geometry.shape(translated_geom).geoms[0].exterior.coords[0] 30 | ) 31 | 32 | assert first_coord_translated[0] - xoff == first_coord[0] 33 | assert first_coord_translated[1] - yoff == first_coord[1] 34 | -------------------------------------------------------------------------------- /python/tests_old/algorithm/test_area.py: -------------------------------------------------------------------------------- 1 | import geoarrow.rust.compute as grc 2 | import geoarrow.rust.core as gars 3 | import geodatasets 4 | import geopandas as gpd 5 | import numpy as np 6 | import pyarrow as pa 7 | 8 | nybb_path = geodatasets.get_path("nybb") 9 | 10 | 11 | def test_area(): 12 | gdf = gpd.read_file(nybb_path) 13 | shapely_area = gdf.geometry.area 14 | assert isinstance(gdf, gpd.GeoDataFrame) 15 | 16 | table = gars.from_geopandas(gdf) 17 | ga_area = grc.area(gars.geometry_col(table)) 18 | pa_arr = pa.chunked_array(ga_area) 19 | assert pa_arr.num_chunks == 1 20 | 21 | pa_area = pa_arr.chunk(0) 22 | assert np.allclose(shapely_area, pa_area) 23 | -------------------------------------------------------------------------------- /python/tests_old/algorithm/test_explode.py: -------------------------------------------------------------------------------- 1 | # import geoarrow.rust.core as gars 2 | 3 | # import geopandas as gpd 4 | # import pandas as pd 5 | # from geoarrow.rust.core import GeoTable 6 | 7 | # gdf = gpd.read_file(gpd.datasets.get_path('nybb')) 8 | 9 | # table = GeoTable.from_geopandas(gdf) 10 | # exploded_table = table.explode() 11 | # round_trip_gdf = exploded_table.to_geopandas() 12 | # geopandas_impl = gdf.explode(index_parts=False) 13 | 14 | # all(round_trip_gdf.geometry.reset_index(drop=True) == geopandas_impl.geometry.reset_index(drop=True)) 15 | # # True! Yay! 16 | 17 | # ### 18 | # # Perf testing 19 | # large = pd.concat([gdf] * 1000) 20 | 21 | # table = GeoTable.from_geopandas(large) 22 | # %timeit exploded_table = table.explode() 23 | # # 590 µs ± 33.2 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) 24 | 25 | # %timeit gdf_exp = large.explode(index_parts=False) 26 | # # 262 ms ± 10.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 27 | -------------------------------------------------------------------------------- /python/tests_old/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests_old/core/__init__.py -------------------------------------------------------------------------------- /python/tests_old/core/test_array.py: -------------------------------------------------------------------------------- 1 | import geodatasets 2 | import geopandas as gpd 3 | import shapely 4 | import shapely.testing 5 | from geoarrow.rust.core import from_geopandas, geometry_col 6 | 7 | nybb_path = geodatasets.get_path("nybb") 8 | 9 | 10 | def test_indexing(): 11 | gdf = gpd.read_file(nybb_path) 12 | table = from_geopandas(gdf) 13 | geometry = geometry_col(table) 14 | 15 | shapely_scalar = shapely.geometry.shape(geometry[0]) 16 | assert gdf.geometry[0] == shapely_scalar 17 | 18 | shapely_scalar = shapely.geometry.shape(geometry[-1]) 19 | assert gdf.geometry.iloc[-1] == shapely_scalar 20 | -------------------------------------------------------------------------------- /python/tests_old/core/test_geometry_type.py: -------------------------------------------------------------------------------- 1 | import geodatasets 2 | import geopandas as gpd 3 | from geoarrow.rust.core import from_geopandas, geometry_col 4 | from geoarrow.rust.core.enums import CoordType, Dimension 5 | 6 | nybb_path = geodatasets.get_path("nybb") 7 | 8 | 9 | def test_geometry_type(): 10 | gdf = gpd.read_file(nybb_path) 11 | table = from_geopandas(gdf) 12 | geometry = geometry_col(table) 13 | geometry_type = geometry.type 14 | 15 | assert geometry_type.coord_type == CoordType.Interleaved 16 | assert geometry_type.dimension == Dimension.XY 17 | 18 | # TODO: come back to this 19 | # assert geometry_type == NativeType( 20 | # "multipolygon", 21 | # Dimension.XY, 22 | # CoordType.Interleaved, 23 | # ) 24 | -------------------------------------------------------------------------------- /python/tests_old/interop/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests_old/interop/__init__.py -------------------------------------------------------------------------------- /python/tests_old/interop/test_geopandas.py: -------------------------------------------------------------------------------- 1 | import geoarrow.rust.core as gars 2 | import geodatasets 3 | import geopandas as gpd 4 | from geopandas.testing import assert_geodataframe_equal 5 | 6 | nybb_path = geodatasets.get_path("nybb") 7 | 8 | 9 | # Test it works without error 10 | # Superseded by full assertion when CRS is fixed 11 | def test_geopandas_round_trip(): 12 | gdf = gpd.read_file(nybb_path) 13 | assert isinstance(gdf, gpd.GeoDataFrame) 14 | table = gars.from_geopandas(gdf) 15 | retour = gars.to_geopandas(table) 16 | assert_geodataframe_equal(gdf, retour) 17 | -------------------------------------------------------------------------------- /python/tests_old/interop/test_wkt.py: -------------------------------------------------------------------------------- 1 | import pyarrow as pa 2 | import pytest 3 | import shapely 4 | from geoarrow.rust.core import from_wkt, to_shapely 5 | from shapely.testing import assert_geometries_equal 6 | 7 | 8 | @pytest.mark.skip 9 | def test_from_wkt(): 10 | s = [ 11 | "POINT (3 2)", 12 | "POINT (0 2)", 13 | "POINT (1 4)", 14 | "POINT (3 2)", 15 | "POINT (0 2)", 16 | "POINT (1 4)", 17 | ] 18 | shapely_arr = shapely.from_wkt(s) 19 | geo_arr = from_wkt(pa.array(s)) 20 | assert_geometries_equal(shapely_arr, to_shapely(geo_arr)) 21 | 22 | 23 | @pytest.mark.skip 24 | def test_from_wkt_chunked(): 25 | s1 = ["POINT (3 2)", "POINT (0 2)", "POINT (1 4)"] 26 | s2 = ["POINT (3 2)", "POINT (0 2)", "POINT (1 4)"] 27 | ca = pa.chunked_array([pa.array(s1), pa.array(s2)]) 28 | shapely_arr = shapely.from_wkt(s1 + s2) 29 | geo_arr = from_wkt(ca) 30 | assert_geometries_equal(shapely_arr, to_shapely(geo_arr)) 31 | -------------------------------------------------------------------------------- /python/tests_old/io/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/python/tests_old/io/__init__.py -------------------------------------------------------------------------------- /python/tests_old/io/test_pyogrio.py: -------------------------------------------------------------------------------- 1 | import geodatasets 2 | import geopandas as gpd 3 | import pytest 4 | import shapely.testing 5 | from geoarrow.rust.core import geometry_col, read_pyogrio, to_shapely 6 | 7 | nybb_path = geodatasets.get_path("nybb") 8 | 9 | 10 | def test_read_pyogrio(): 11 | _table = read_pyogrio(nybb_path) 12 | # gdf = gpd.read_file(nybb_path) 13 | # shapely.testing.assert_geometries_equal( 14 | # to_shapely(geometry_col(table)), gdf.geometry 15 | # ) 16 | 17 | 18 | @pytest.mark.xfail( 19 | reason=( 20 | "to_shapely currently failing on WKB input with:\n" 21 | "Exception: General error: Unexpected extension name geoarrow.wkb" 22 | ) 23 | ) 24 | def test_read_pyogrio_round_trip(): 25 | table = read_pyogrio(nybb_path) 26 | gdf = gpd.read_file(nybb_path) 27 | shapely.testing.assert_geometries_equal( 28 | to_shapely(geometry_col(table)), gdf.geometry 29 | ) 30 | -------------------------------------------------------------------------------- /python/tests_old/io/test_shapefile.py: -------------------------------------------------------------------------------- 1 | import geodatasets 2 | from geoarrow.rust.core import get_crs 3 | from geoarrow.rust.io import read_shapefile 4 | from pyproj import CRS 5 | 6 | 7 | def test_read_shapefile(): 8 | shp_path = geodatasets.get_path("ny.bb") 9 | 10 | table = read_shapefile(shp_path) 11 | crs = get_crs(table) 12 | assert crs is not None 13 | 14 | assert crs == CRS.from_epsg(2263) 15 | 16 | assert len(table) == 5 17 | -------------------------------------------------------------------------------- /python/tests_old/utils.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | 4 | def get_repo_root() -> Path: 5 | current_dir = Path(".").absolute() 6 | 7 | while current_dir.stem != "geoarrow-rs": 8 | if current_dir == Path("/"): 9 | raise ValueError("Could not find repo root; is it named geoarrow-rs?") 10 | current_dir = current_dir.parent 11 | 12 | return current_dir 13 | 14 | 15 | REPO_ROOT = get_repo_root() 16 | FIXTURES_DIR = REPO_ROOT / "fixtures" 17 | 18 | -------------------------------------------------------------------------------- /rust/geoarrow-array/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "geoarrow-array" 4 | version = { workspace = true } 5 | authors = { workspace = true } 6 | edition = { workspace = true } 7 | license = { workspace = true } 8 | repository = { workspace = true } 9 | description = "GeoArrow array definitions." 10 | categories = { workspace = true } 11 | rust-version = { workspace = true } 12 | 13 | [features] 14 | geozero = ["dep:geozero", "dep:arrow-json"] 15 | # Include test data in public API 16 | # TODO: Remove geo-types here 17 | test-data = ["dep:geoarrow-test", "dep:geo-types"] 18 | 19 | [dependencies] 20 | arrow-array = { workspace = true } 21 | arrow-buffer = { workspace = true } 22 | arrow-json = { workspace = true, optional = true } 23 | arrow-schema = { workspace = true } 24 | geo-traits = { workspace = true } 25 | geo-types = { workspace = true, optional = true } 26 | geoarrow-schema = { workspace = true } 27 | geoarrow-test = { workspace = true, optional = true } 28 | geozero = { workspace = true, optional = true } 29 | num-traits = { workspace = true } 30 | wkb = { workspace = true } 31 | wkt = { workspace = true } 32 | 33 | [dev-dependencies] 34 | geo = { workspace = true } 35 | geo-types = { workspace = true } 36 | geoarrow-test = { workspace = true } 37 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/array/coord/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains implementations for how to encode arrays of coordinates for all other geometry array 2 | //! types. 3 | //! 4 | //! Coordinates can be either _interleaved_, where they're represented as a `FixedSizeList`, or 5 | //! _separated_, where they're represented with a `StructArray`. 6 | 7 | mod combined; 8 | mod interleaved; 9 | mod separated; 10 | 11 | pub use combined::CoordBuffer; 12 | pub use interleaved::InterleavedCoordBuffer; 13 | pub use separated::SeparatedCoordBuffer; 14 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/builder/coord/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains implementations for how to encode arrays of coordinates for all other geometry array 2 | //! types. 3 | //! 4 | //! Coordinates can be either _interleaved_, where they're represented as a `FixedSizeList`, or 5 | //! _separated_, where they're represented with a `StructArray`. 6 | 7 | mod combined; 8 | mod interleaved; 9 | mod separated; 10 | 11 | pub use combined::CoordBufferBuilder; 12 | pub use interleaved::InterleavedCoordBufferBuilder; 13 | pub use separated::SeparatedCoordBufferBuilder; 14 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/builder/mod.rs: -------------------------------------------------------------------------------- 1 | //! Push-based APIs for constructing arrays. 2 | 3 | mod coord; 4 | pub(crate) mod geo_trait_wrappers; 5 | mod geometry; 6 | mod geometrycollection; 7 | mod linestring; 8 | mod mixed; 9 | mod multilinestring; 10 | mod multipoint; 11 | mod multipolygon; 12 | mod offsets; 13 | mod point; 14 | mod polygon; 15 | mod rect; 16 | mod wkb; 17 | 18 | pub use coord::{CoordBufferBuilder, InterleavedCoordBufferBuilder, SeparatedCoordBufferBuilder}; 19 | pub use geometry::GeometryBuilder; 20 | pub(crate) use geometry::TypeId; 21 | pub use geometrycollection::GeometryCollectionBuilder; 22 | pub use linestring::LineStringBuilder; 23 | pub(crate) use mixed::MixedGeometryBuilder; 24 | pub use multilinestring::MultiLineStringBuilder; 25 | pub use multipoint::MultiPointBuilder; 26 | pub use multipolygon::MultiPolygonBuilder; 27 | pub(crate) use offsets::OffsetsBuilder; 28 | pub use point::PointBuilder; 29 | pub use polygon::PolygonBuilder; 30 | pub use rect::RectBuilder; 31 | pub use wkb::WkbBuilder; 32 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/capacity/mod.rs: -------------------------------------------------------------------------------- 1 | //! Counters for managing buffer lengths for each geometry array type. 2 | //! 3 | //! The most memory-efficient way to construct an array from a set of geometries is to make a 4 | //! first pass over these geometries to count exactly how big each underlying buffer of the Arrow 5 | //! array must be, allocate _once_ for exactly what you need, and then fill those buffers in a 6 | //! second pass. Capacity counters help with this process. 7 | 8 | mod geometry; 9 | mod geometrycollection; 10 | mod linestring; 11 | mod mixed; 12 | mod multilinestring; 13 | mod multipoint; 14 | mod multipolygon; 15 | mod point; 16 | mod polygon; 17 | mod wkb; 18 | 19 | pub use geometry::GeometryCapacity; 20 | pub use geometrycollection::GeometryCollectionCapacity; 21 | pub use linestring::LineStringCapacity; 22 | pub(crate) use mixed::MixedCapacity; 23 | pub use multilinestring::MultiLineStringCapacity; 24 | pub use multipoint::MultiPointCapacity; 25 | pub use multipolygon::MultiPolygonCapacity; 26 | pub use polygon::PolygonCapacity; 27 | pub use wkb::WkbCapacity; 28 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/array/geometry.rs: -------------------------------------------------------------------------------- 1 | use geozero::{GeomProcessor, GeozeroGeometry}; 2 | 3 | use crate::array::GeometryArray; 4 | use crate::geozero::export::scalar::process_geometry; 5 | use crate::{GeoArrowArray, GeoArrowArrayAccessor}; 6 | 7 | impl GeozeroGeometry for GeometryArray { 8 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 9 | where 10 | Self: Sized, 11 | { 12 | let num_geometries = self.len(); 13 | processor.geometrycollection_begin(num_geometries, 0)?; 14 | 15 | for geom_idx in 0..num_geometries { 16 | process_geometry(&self.value(geom_idx).unwrap(), geom_idx, processor)?; 17 | } 18 | 19 | processor.geometrycollection_end(num_geometries - 1)?; 20 | Ok(()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/array/geometrycollection.rs: -------------------------------------------------------------------------------- 1 | use geozero::{GeomProcessor, GeozeroGeometry}; 2 | 3 | use crate::array::GeometryCollectionArray; 4 | use crate::geozero::export::scalar::process_geometry_collection; 5 | use crate::{GeoArrowArray, GeoArrowArrayAccessor}; 6 | 7 | impl GeozeroGeometry for GeometryCollectionArray { 8 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 9 | where 10 | Self: Sized, 11 | { 12 | let num_geometries = self.len(); 13 | processor.geometrycollection_begin(num_geometries, 0)?; 14 | 15 | for geom_idx in 0..num_geometries { 16 | process_geometry_collection(&self.value(geom_idx).unwrap(), geom_idx, processor)?; 17 | } 18 | 19 | processor.geometrycollection_end(num_geometries - 1)?; 20 | Ok(()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/array/linestring.rs: -------------------------------------------------------------------------------- 1 | use geozero::{GeomProcessor, GeozeroGeometry}; 2 | 3 | use crate::array::LineStringArray; 4 | use crate::geozero::export::scalar::process_line_string; 5 | use crate::{GeoArrowArray, GeoArrowArrayAccessor}; 6 | 7 | impl GeozeroGeometry for LineStringArray { 8 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 9 | where 10 | Self: Sized, 11 | { 12 | let num_geometries = self.len(); 13 | processor.geometrycollection_begin(num_geometries, 0)?; 14 | 15 | for geom_idx in 0..num_geometries { 16 | process_line_string(&self.value(geom_idx).unwrap(), geom_idx, processor)?; 17 | } 18 | 19 | processor.geometrycollection_end(num_geometries - 1)?; 20 | Ok(()) 21 | } 22 | } 23 | 24 | #[cfg(test)] 25 | mod test { 26 | use geoarrow_schema::CoordType; 27 | use geozero::ToWkt; 28 | 29 | use crate::test::linestring::ls_array; 30 | 31 | #[test] 32 | fn geozero_process_geom() -> geozero::error::Result<()> { 33 | let arr = ls_array(CoordType::Interleaved); 34 | let wkt = ToWkt::to_wkt(&arr)?; 35 | let expected = "GEOMETRYCOLLECTION(LINESTRING(0 1,1 2),LINESTRING EMPTY,LINESTRING(3 4,5 6),LINESTRING EMPTY)"; 36 | assert_eq!(wkt, expected); 37 | Ok(()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/array/mod.rs: -------------------------------------------------------------------------------- 1 | mod geometry; 2 | mod geometrycollection; 3 | mod linestring; 4 | mod multilinestring; 5 | mod multipoint; 6 | mod multipolygon; 7 | mod point; 8 | mod polygon; 9 | mod rect; 10 | mod wkb; 11 | mod wkt; 12 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/array/point.rs: -------------------------------------------------------------------------------- 1 | use geozero::{GeomProcessor, GeozeroGeometry}; 2 | 3 | use crate::array::PointArray; 4 | use crate::geozero::export::scalar::process_point; 5 | use crate::{GeoArrowArray, GeoArrowArrayAccessor}; 6 | 7 | impl GeozeroGeometry for PointArray { 8 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 9 | where 10 | Self: Sized, 11 | { 12 | let num_geometries = self.len(); 13 | processor.geometrycollection_begin(num_geometries, 0)?; 14 | 15 | for idx in 0..num_geometries { 16 | process_point(&self.value(idx).unwrap(), idx, processor)?; 17 | } 18 | 19 | processor.geometrycollection_end(num_geometries)?; 20 | Ok(()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implementation to export GeoArrow arrays through the geozero API. 2 | 3 | mod array; 4 | mod data_source; 5 | pub(crate) mod scalar; 6 | 7 | pub use data_source::GeozeroRecordBatchReader; 8 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/geometry_collection.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::GeometryCollectionTrait; 2 | use geozero::{GeomProcessor, GeozeroGeometry}; 3 | 4 | use super::process_geometry; 5 | use crate::scalar::GeometryCollection; 6 | 7 | pub(crate) fn process_geometry_collection( 8 | geom: &impl GeometryCollectionTrait, 9 | geom_idx: usize, 10 | processor: &mut P, 11 | ) -> geozero::error::Result<()> { 12 | processor.geometrycollection_begin(geom.num_geometries(), geom_idx)?; 13 | 14 | for (i, geometry) in geom.geometries().enumerate() { 15 | process_geometry(&geometry, i, processor)?; 16 | } 17 | 18 | processor.geometrycollection_end(geom_idx)?; 19 | Ok(()) 20 | } 21 | 22 | impl GeozeroGeometry for GeometryCollection<'_> { 23 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 24 | where 25 | Self: Sized, 26 | { 27 | process_geometry_collection(&self, 0, processor) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/linestring.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::LineStringTrait; 2 | use geozero::{GeomProcessor, GeozeroGeometry}; 3 | 4 | use super::process_coord; 5 | use crate::scalar::LineString; 6 | 7 | pub(crate) fn process_line_string( 8 | geom: &impl LineStringTrait, 9 | geom_idx: usize, 10 | processor: &mut P, 11 | ) -> geozero::error::Result<()> { 12 | processor.linestring_begin(true, geom.num_coords(), geom_idx)?; 13 | 14 | for (coord_idx, coord) in geom.coords().enumerate() { 15 | process_coord(&coord, coord_idx, processor)?; 16 | } 17 | 18 | processor.linestring_end(true, geom_idx)?; 19 | Ok(()) 20 | } 21 | 22 | impl GeozeroGeometry for LineString<'_> { 23 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 24 | where 25 | Self: Sized, 26 | { 27 | process_line_string(self, 0, processor) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/mod.rs: -------------------------------------------------------------------------------- 1 | mod coord; 2 | mod geometry; 3 | mod geometry_collection; 4 | mod linestring; 5 | mod multilinestring; 6 | mod multipoint; 7 | mod multipolygon; 8 | mod point; 9 | mod polygon; 10 | mod rect; 11 | 12 | pub(crate) use coord::process_coord; 13 | pub(crate) use geometry::process_geometry; 14 | pub(crate) use geometry_collection::process_geometry_collection; 15 | pub(crate) use linestring::process_line_string; 16 | pub(crate) use multilinestring::process_multi_line_string; 17 | pub(crate) use multipoint::process_multi_point; 18 | pub(crate) use multipolygon::process_multi_polygon; 19 | pub(crate) use point::{process_point, process_point_as_coord}; 20 | pub(crate) use polygon::process_polygon; 21 | pub(crate) use rect::process_rect; 22 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/multilinestring.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::{LineStringTrait, MultiLineStringTrait}; 2 | use geozero::{GeomProcessor, GeozeroGeometry}; 3 | 4 | use super::process_coord; 5 | use crate::scalar::MultiLineString; 6 | 7 | pub(crate) fn process_multi_line_string( 8 | geom: &impl MultiLineStringTrait, 9 | geom_idx: usize, 10 | processor: &mut P, 11 | ) -> geozero::error::Result<()> { 12 | processor.multilinestring_begin(geom.num_line_strings(), geom_idx)?; 13 | 14 | for (line_idx, line) in geom.line_strings().enumerate() { 15 | processor.linestring_begin(false, line.num_coords(), line_idx)?; 16 | 17 | for (coord_idx, coord) in line.coords().enumerate() { 18 | process_coord(&coord, coord_idx, processor)?; 19 | } 20 | 21 | processor.linestring_end(false, line_idx)?; 22 | } 23 | 24 | processor.multilinestring_end(geom_idx)?; 25 | Ok(()) 26 | } 27 | 28 | impl GeozeroGeometry for MultiLineString<'_> { 29 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 30 | where 31 | Self: Sized, 32 | { 33 | process_multi_line_string(self, 0, processor) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/multipoint.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::MultiPointTrait; 2 | use geozero::{GeomProcessor, GeozeroGeometry}; 3 | 4 | use super::process_point_as_coord; 5 | use crate::scalar::MultiPoint; 6 | 7 | pub(crate) fn process_multi_point( 8 | geom: &impl MultiPointTrait, 9 | geom_idx: usize, 10 | processor: &mut P, 11 | ) -> geozero::error::Result<()> { 12 | processor.multipoint_begin(geom.num_points(), geom_idx)?; 13 | 14 | for (point_idx, point) in geom.points().enumerate() { 15 | process_point_as_coord(&point, point_idx, processor)?; 16 | } 17 | 18 | processor.multipoint_end(geom_idx)?; 19 | Ok(()) 20 | } 21 | 22 | impl GeozeroGeometry for MultiPoint<'_> { 23 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 24 | where 25 | Self: Sized, 26 | { 27 | process_multi_point(self, 0, processor) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/multipolygon.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::MultiPolygonTrait; 2 | use geozero::{GeomProcessor, GeozeroGeometry}; 3 | 4 | use super::process_polygon; 5 | use crate::scalar::MultiPolygon; 6 | 7 | pub(crate) fn process_multi_polygon( 8 | geom: &impl MultiPolygonTrait, 9 | geom_idx: usize, 10 | processor: &mut P, 11 | ) -> geozero::error::Result<()> { 12 | processor.multipolygon_begin(geom.num_polygons(), geom_idx)?; 13 | 14 | for (polygon_idx, polygon) in geom.polygons().enumerate() { 15 | process_polygon(&polygon, false, polygon_idx, processor)?; 16 | } 17 | 18 | processor.multipolygon_end(geom_idx)?; 19 | Ok(()) 20 | } 21 | 22 | impl GeozeroGeometry for MultiPolygon<'_> { 23 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 24 | where 25 | Self: Sized, 26 | { 27 | process_multi_polygon(self, 0, processor) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/export/scalar/rect.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::RectTrait; 2 | use geozero::{GeomProcessor, GeozeroGeometry}; 3 | 4 | use crate::builder::geo_trait_wrappers::RectWrapper; 5 | use crate::geozero::export::scalar::process_polygon; 6 | use crate::scalar::Rect; 7 | 8 | pub(crate) fn process_rect( 9 | geom: &impl RectTrait, 10 | geom_idx: usize, 11 | processor: &mut P, 12 | ) -> geozero::error::Result<()> { 13 | let polygon = RectWrapper::try_new(geom) 14 | .map_err(|err| geozero::error::GeozeroError::Geometry(err.to_string()))?; 15 | process_polygon(&polygon, true, geom_idx, processor) 16 | } 17 | 18 | impl GeozeroGeometry for Rect<'_> { 19 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 20 | where 21 | Self: Sized, 22 | { 23 | process_rect(self, 0, processor) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/import/mod.rs: -------------------------------------------------------------------------------- 1 | //! Import geozero types into GeoArrow arrays 2 | 3 | mod geometry; 4 | mod linestring; 5 | mod multilinestring; 6 | mod multipoint; 7 | mod multipolygon; 8 | mod point; 9 | mod polygon; 10 | mod util; 11 | 12 | pub use geometry::ToGeometryArray; 13 | pub use linestring::ToLineStringArray; 14 | pub use multilinestring::ToMultiLineStringArray; 15 | pub use multipoint::ToMultiPointArray; 16 | pub use multipolygon::ToMultiPolygonArray; 17 | pub use point::ToPointArray; 18 | pub use polygon::ToPolygonArray; 19 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/geozero/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implements the geometry and dataset conversion APIs defined by the [`geozero`] 2 | //! crate. 3 | 4 | pub mod export; 5 | pub mod import; 6 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![warn(missing_docs)] 3 | #![cfg_attr(not(test), deny(unused_crate_dependencies))] 4 | 5 | pub mod array; 6 | pub mod builder; 7 | pub mod capacity; 8 | pub mod cast; 9 | mod eq; 10 | #[cfg(feature = "geozero")] 11 | pub mod geozero; 12 | pub mod scalar; 13 | mod trait_; 14 | pub(crate) mod util; 15 | 16 | pub use trait_::{GeoArrowArray, GeoArrowArrayAccessor, IntoArrow}; 17 | 18 | #[cfg(any(test, feature = "test-data"))] 19 | #[allow(missing_docs)] 20 | pub mod test; 21 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/scalar/coord/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains implementations for how to encode arrays of coordinates for all other geometry array 2 | //! types. 3 | //! 4 | //! Coordinates can be either _interleaved_, where they're represented as a `FixedSizeList`, or 5 | //! _separated_, where they're represented with a `StructArray`. 6 | 7 | mod combined; 8 | mod interleaved; 9 | mod separated; 10 | 11 | pub use combined::Coord; 12 | pub use interleaved::InterleavedCoord; 13 | pub use separated::SeparatedCoord; 14 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/test/geometry.rs: -------------------------------------------------------------------------------- 1 | use geoarrow_schema::{CoordType, GeometryType}; 2 | use geoarrow_test::raw; 3 | 4 | use crate::array::GeometryArray; 5 | use crate::builder::GeometryBuilder; 6 | 7 | pub fn array(coord_type: CoordType, _prefer_multi: bool) -> GeometryArray { 8 | let typ = GeometryType::new(Default::default()).with_coord_type(coord_type); 9 | GeometryBuilder::from_nullable_geometries(&raw::geometry::geoms(), typ) 10 | .unwrap() 11 | .finish() 12 | } 13 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/test/geometrycollection.rs: -------------------------------------------------------------------------------- 1 | use geoarrow_schema::{CoordType, Dimension, GeometryCollectionType}; 2 | use geoarrow_test::raw; 3 | 4 | use crate::array::GeometryCollectionArray; 5 | use crate::builder::GeometryCollectionBuilder; 6 | 7 | pub fn array( 8 | coord_type: CoordType, 9 | dim: Dimension, 10 | _prefer_multi: bool, 11 | ) -> GeometryCollectionArray { 12 | let typ = GeometryCollectionType::new(dim, Default::default()).with_coord_type(coord_type); 13 | let geoms = match dim { 14 | Dimension::XY => raw::geometrycollection::xy::geoms(), 15 | Dimension::XYZ => raw::geometrycollection::xyz::geoms(), 16 | Dimension::XYM => raw::geometrycollection::xym::geoms(), 17 | Dimension::XYZM => raw::geometrycollection::xyzm::geoms(), 18 | }; 19 | 20 | GeometryCollectionBuilder::from_nullable_geometry_collections(&geoms, typ) 21 | .unwrap() 22 | .finish() 23 | } 24 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/test/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | pub mod geometry; 4 | pub mod geometrycollection; 5 | pub mod linestring; 6 | pub mod multilinestring; 7 | pub mod multipoint; 8 | pub mod multipolygon; 9 | pub mod point; 10 | pub mod polygon; 11 | pub mod properties; 12 | pub mod rect; 13 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/test/point.rs: -------------------------------------------------------------------------------- 1 | use geo_types::{Point, point}; 2 | use geoarrow_schema::{CoordType, Dimension, PointType}; 3 | use geoarrow_test::raw; 4 | 5 | use crate::array::PointArray; 6 | use crate::builder::PointBuilder; 7 | 8 | pub(crate) fn p0() -> Point { 9 | point!( 10 | x: 0., y: 1. 11 | ) 12 | } 13 | 14 | pub(crate) fn p1() -> Point { 15 | point!( 16 | x: 1., y: 2. 17 | ) 18 | } 19 | 20 | pub(crate) fn p2() -> Point { 21 | point!( 22 | x: 2., y: 3. 23 | ) 24 | } 25 | 26 | pub(crate) fn point_array(coord_type: CoordType) -> PointArray { 27 | let geoms = [Some(p0()), Some(p1()), None, Some(p2())]; 28 | let typ = PointType::new(Dimension::XY, Default::default()).with_coord_type(coord_type); 29 | PointBuilder::from_nullable_points(geoms.iter().map(|x| x.as_ref()), typ).finish() 30 | } 31 | 32 | pub fn array(coord_type: CoordType, dim: Dimension) -> PointArray { 33 | let typ = PointType::new(dim, Default::default()).with_coord_type(coord_type); 34 | let geoms = match dim { 35 | Dimension::XY => raw::point::xy::geoms(), 36 | Dimension::XYZ => raw::point::xyz::geoms(), 37 | Dimension::XYM => raw::point::xym::geoms(), 38 | Dimension::XYZM => raw::point::xyzm::geoms(), 39 | }; 40 | PointBuilder::from_nullable_points(geoms.iter().map(|x| x.as_ref()), typ).finish() 41 | } 42 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/test/properties.rs: -------------------------------------------------------------------------------- 1 | use arrow_array::{StringArray, UInt8Array}; 2 | 3 | pub(crate) fn u8_array() -> UInt8Array { 4 | UInt8Array::from(vec![1, 2, 3]) 5 | } 6 | 7 | pub(crate) fn string_array() -> StringArray { 8 | vec!["foo", "bar", "baz"].into() 9 | } 10 | -------------------------------------------------------------------------------- /rust/geoarrow-array/src/test/rect.rs: -------------------------------------------------------------------------------- 1 | use geo_types::{Rect, coord}; 2 | use geoarrow_schema::{BoxType, Dimension}; 3 | 4 | use crate::array::RectArray; 5 | use crate::builder::RectBuilder; 6 | 7 | pub(crate) fn r0() -> Rect { 8 | Rect::new(coord! { x: 10., y: 20. }, coord! { x: 30., y: 10. }) 9 | } 10 | 11 | pub(crate) fn r1() -> Rect { 12 | Rect::new(coord! { x: 100., y: 200. }, coord! { x: 300., y: 100. }) 13 | } 14 | 15 | pub(crate) fn r_array() -> RectArray { 16 | let geoms = [Some(r0()), None, Some(r1()), None]; 17 | let typ = BoxType::new(Dimension::XY, Default::default()); 18 | RectBuilder::from_nullable_rects(geoms.iter().map(|x| x.as_ref()), typ).finish() 19 | } 20 | -------------------------------------------------------------------------------- /rust/geoarrow-cast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-cast" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | license = { workspace = true } 7 | repository = { workspace = true } 8 | description = "Functions for converting from one GeoArrow geometry type to another." 9 | categories = { workspace = true } 10 | rust-version = { workspace = true } 11 | 12 | 13 | [dependencies] 14 | arrow-schema = { workspace = true } 15 | geo-traits = { workspace = true } 16 | geoarrow-array = { workspace = true } 17 | geoarrow-schema = { workspace = true } 18 | wkt = { workspace = true } 19 | 20 | [dev-dependencies] 21 | geoarrow-array = { workspace = true, features = ["test-data"] } 22 | geoarrow-test = { workspace = true } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-cast/README.md: -------------------------------------------------------------------------------- 1 | # geoarrow-cast 2 | 3 | Functions for converting from one GeoArrow geometry type to another. 4 | -------------------------------------------------------------------------------- /rust/geoarrow-cast/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![warn(missing_docs)] 3 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 4 | 5 | pub mod cast; 6 | pub mod downcast; 7 | -------------------------------------------------------------------------------- /rust/geoarrow-flatgeobuf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-flatgeobuf" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | license = { workspace = true } 7 | repository = { workspace = true } 8 | description = "Reader and writer for FlatGeobuf files to GeoArrow memory." 9 | categories = { workspace = true } 10 | rust-version = { workspace = true } 11 | 12 | 13 | [dependencies] 14 | arrow-schema = { workspace = true } 15 | flatgeobuf = { workspace = true } 16 | geoarrow-array = { workspace = true, features = ["geozero"] } 17 | geoarrow-schema = { workspace = true } 18 | geozero = { workspace = true } 19 | 20 | [dev-dependencies] 21 | arrow-array = { workspace = true } 22 | wkt = { workspace = true } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-flatgeobuf/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/rust/geoarrow-flatgeobuf/README.md -------------------------------------------------------------------------------- /rust/geoarrow-flatgeobuf/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(test), deny(unused_crate_dependencies))] 2 | 3 | pub mod writer; 4 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-geos" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | license = { workspace = true } 7 | repository = { workspace = true } 8 | description = "Rust implementation of GeoArrow" 9 | categories = { workspace = true } 10 | rust-version = { workspace = true } 11 | 12 | 13 | [dependencies] 14 | arrow-array = { workspace = true } 15 | arrow-schema = { workspace = true } 16 | geo-traits = { workspace = true } 17 | geoarrow-array = { workspace = true, features = ["test-data"] } 18 | geoarrow-schema = { workspace = true } 19 | geos = { workspace = true } 20 | 21 | [dev-dependencies] 22 | geos = { workspace = true, features = ["static"] } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/README.md: -------------------------------------------------------------------------------- 1 | # geoarrow-geos 2 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/mod.rs: -------------------------------------------------------------------------------- 1 | mod scalar; 2 | 3 | pub use scalar::to_geos_geometry; 4 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/geometry.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::GeometryTrait; 2 | 3 | use crate::export::scalar::geometrycollection::to_geos_geometry_collection; 4 | use crate::export::scalar::linestring::to_geos_line_string; 5 | use crate::export::scalar::multilinestring::to_geos_multi_line_string; 6 | use crate::export::scalar::multipoint::to_geos_multi_point; 7 | use crate::export::scalar::multipolygon::to_geos_multi_polygon; 8 | use crate::export::scalar::point::to_geos_point; 9 | use crate::export::scalar::polygon::to_geos_polygon; 10 | 11 | pub fn to_geos_geometry( 12 | geometry: &impl GeometryTrait, 13 | ) -> std::result::Result { 14 | use geo_traits::GeometryType::*; 15 | 16 | match geometry.as_type() { 17 | Point(g) => to_geos_point(g), 18 | LineString(g) => to_geos_line_string(g), 19 | Polygon(g) => to_geos_polygon(g), 20 | MultiPoint(g) => to_geos_multi_point(g), 21 | MultiLineString(g) => to_geos_multi_line_string(g), 22 | MultiPolygon(g) => to_geos_multi_polygon(g), 23 | GeometryCollection(g) => to_geos_geometry_collection(g), 24 | Rect(_) => panic!("Unsupported rect in conversion to GEOS"), 25 | Triangle(_) => panic!("Unsupported triangle in conversion to GEOS"), 26 | Line(_) => panic!("Unsupported Line in conversion to GEOS"), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/geometrycollection.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::GeometryCollectionTrait; 2 | 3 | use crate::export::scalar::to_geos_geometry; 4 | 5 | pub(crate) fn to_geos_geometry_collection( 6 | gc: &impl GeometryCollectionTrait, 7 | ) -> std::result::Result { 8 | geos::Geometry::create_geometry_collection( 9 | gc.geometries() 10 | .map(|geometry| to_geos_geometry(&geometry)) 11 | .collect::, geos::Error>>()?, 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/linestring.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::LineStringTrait; 2 | 3 | use crate::export::scalar::coord::{coords_to_geos, dims_to_geos}; 4 | 5 | pub(crate) fn to_geos_line_string( 6 | line_string: &impl LineStringTrait, 7 | ) -> std::result::Result { 8 | let dims = dims_to_geos(line_string.dim()); 9 | let coord_seq = coords_to_geos(line_string.coords(), dims)?; 10 | geos::Geometry::create_line_string(coord_seq) 11 | } 12 | 13 | pub(crate) fn to_geos_linear_ring( 14 | line_string: &impl LineStringTrait, 15 | ) -> std::result::Result { 16 | let dims = dims_to_geos(line_string.dim()); 17 | let coord_seq = coords_to_geos(line_string.coords(), dims)?; 18 | geos::Geometry::create_linear_ring(coord_seq) 19 | } 20 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/mod.rs: -------------------------------------------------------------------------------- 1 | mod coord; 2 | mod geometry; 3 | mod geometrycollection; 4 | mod linestring; 5 | mod multilinestring; 6 | mod multipoint; 7 | mod multipolygon; 8 | mod point; 9 | mod polygon; 10 | 11 | pub use geometry::to_geos_geometry; 12 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/multilinestring.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::MultiLineStringTrait; 2 | 3 | use crate::export::scalar::linestring::to_geos_line_string; 4 | 5 | pub(crate) fn to_geos_multi_line_string( 6 | multi_line_string: &impl MultiLineStringTrait, 7 | ) -> std::result::Result { 8 | geos::Geometry::create_multiline_string( 9 | multi_line_string 10 | .line_strings() 11 | .map(|line| to_geos_line_string(&line)) 12 | .collect::, geos::Error>>()?, 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/multipoint.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::MultiPointTrait; 2 | 3 | use crate::export::scalar::point::to_geos_point; 4 | 5 | pub(crate) fn to_geos_multi_point( 6 | multi_point: &impl MultiPointTrait, 7 | ) -> std::result::Result { 8 | geos::Geometry::create_multipoint( 9 | multi_point 10 | .points() 11 | .map(|point| to_geos_point(&point)) 12 | .collect::, geos::Error>>()?, 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/multipolygon.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::MultiPolygonTrait; 2 | 3 | use crate::export::scalar::polygon::to_geos_polygon; 4 | 5 | pub(crate) fn to_geos_multi_polygon( 6 | multi_polygon: &impl MultiPolygonTrait, 7 | ) -> std::result::Result { 8 | geos::Geometry::create_multipolygon( 9 | multi_polygon 10 | .polygons() 11 | .map(|polygon| to_geos_polygon(&polygon)) 12 | .collect::, geos::Error>>()?, 13 | ) 14 | } 15 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/point.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::PointTrait; 2 | 3 | use crate::export::scalar::coord::coord_to_geos; 4 | 5 | pub(crate) fn to_geos_point( 6 | point: &impl PointTrait, 7 | ) -> std::result::Result { 8 | if let Some(coord) = point.coord() { 9 | let coord_seq = coord_to_geos(&coord)?; 10 | Ok(geos::Geometry::create_point(coord_seq)?) 11 | } else { 12 | Ok(geos::Geometry::create_empty_point()?) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/export/scalar/polygon.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::PolygonTrait; 2 | 3 | use crate::export::scalar::linestring::to_geos_linear_ring; 4 | 5 | pub(crate) fn to_geos_polygon( 6 | polygon: &impl PolygonTrait, 7 | ) -> std::result::Result { 8 | if let Some(exterior) = polygon.exterior() { 9 | let exterior = to_geos_linear_ring(&exterior)?; 10 | let interiors = polygon 11 | .interiors() 12 | .map(|interior| to_geos_linear_ring(&interior)) 13 | .collect::, geos::Error>>()?; 14 | geos::Geometry::create_polygon(exterior, interiors) 15 | } else { 16 | geos::Geometry::create_empty_polygon() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/import/array/mod.rs: -------------------------------------------------------------------------------- 1 | mod geometry; 2 | mod geometrycollection; 3 | mod linestring; 4 | mod multilinestring; 5 | mod multipoint; 6 | mod multipolygon; 7 | mod point; 8 | mod polygon; 9 | mod wkb; 10 | 11 | use arrow_schema::extension::ExtensionType; 12 | use geoarrow_schema::error::GeoArrowResult; 13 | 14 | pub trait FromGEOS: Sized { 15 | type GeoArrowType: ExtensionType; 16 | 17 | /// Convert a sequence of GEOS geometries to a GeoArrow array. 18 | fn from_geos( 19 | geoms: impl IntoIterator>, 20 | typ: Self::GeoArrowType, 21 | ) -> GeoArrowResult; 22 | } 23 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/import/array/wkb.rs: -------------------------------------------------------------------------------- 1 | use arrow_array::OffsetSizeTrait; 2 | use geoarrow_array::array::GenericWkbArray; 3 | use geoarrow_array::builder::WkbBuilder; 4 | use geoarrow_schema::WkbType; 5 | use geoarrow_schema::error::GeoArrowResult; 6 | 7 | use crate::import::array::FromGEOS; 8 | use crate::import::scalar::GEOSGeometry; 9 | 10 | impl FromGEOS for WkbBuilder { 11 | type GeoArrowType = WkbType; 12 | 13 | fn from_geos( 14 | geoms: impl IntoIterator>, 15 | typ: Self::GeoArrowType, 16 | ) -> GeoArrowResult { 17 | let geoms = geoms 18 | .into_iter() 19 | .map(|geom| geom.map(GEOSGeometry::new)) 20 | .collect::>(); 21 | Ok(Self::from_nullable_geometries(&geoms, typ)) 22 | } 23 | } 24 | 25 | impl FromGEOS for GenericWkbArray { 26 | type GeoArrowType = WkbType; 27 | 28 | fn from_geos( 29 | geoms: impl IntoIterator>, 30 | typ: Self::GeoArrowType, 31 | ) -> GeoArrowResult { 32 | Ok(WkbBuilder::from_geos(geoms, typ)?.finish()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/import/mod.rs: -------------------------------------------------------------------------------- 1 | mod array; 2 | pub mod scalar; 3 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/import/scalar/coord.rs: -------------------------------------------------------------------------------- 1 | use geo_traits::CoordTrait; 2 | 3 | pub struct GEOSConstCoord { 4 | pub(crate) coords: geos::CoordSeq, 5 | pub(crate) geom_index: usize, 6 | pub(crate) dim: geo_traits::Dimensions, 7 | } 8 | 9 | impl CoordTrait for GEOSConstCoord { 10 | type T = f64; 11 | 12 | fn dim(&self) -> geo_traits::Dimensions { 13 | self.dim 14 | } 15 | 16 | fn nth_or_panic(&self, n: usize) -> Self::T { 17 | match n { 18 | 0 => self.coords.get_x(self.geom_index).unwrap(), 19 | 1 => self.coords.get_y(self.geom_index).unwrap(), 20 | 2 => self.coords.get_z(self.geom_index).unwrap(), 21 | _ => panic!(), 22 | } 23 | } 24 | 25 | fn x(&self) -> Self::T { 26 | self.coords.get_x(self.geom_index).unwrap() 27 | } 28 | 29 | fn y(&self) -> Self::T { 30 | self.coords.get_y(self.geom_index).unwrap() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/import/scalar/mod.rs: -------------------------------------------------------------------------------- 1 | mod coord; 2 | mod geometry; 3 | mod geometrycollection; 4 | mod linearring; 5 | mod linestring; 6 | mod multilinestring; 7 | mod multipoint; 8 | mod multipolygon; 9 | mod point; 10 | mod polygon; 11 | 12 | pub use geometry::GEOSGeometry; 13 | pub use geometrycollection::GEOSGeometryCollection; 14 | pub use linearring::GEOSConstLinearRing; 15 | pub use linestring::{GEOSConstLineString, GEOSLineString}; 16 | pub use multilinestring::GEOSMultiLineString; 17 | pub use multipoint::GEOSMultiPoint; 18 | pub use multipolygon::GEOSMultiPolygon; 19 | pub use point::{GEOSConstPoint, GEOSPoint}; 20 | pub use polygon::{GEOSConstPolygon, GEOSPolygon}; 21 | -------------------------------------------------------------------------------- /rust/geoarrow-geos/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(test), deny(unused_crate_dependencies))] 2 | 3 | pub mod export; 4 | pub mod import; 5 | -------------------------------------------------------------------------------- /rust/geoarrow-schema/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "geoarrow-schema" 4 | version = { workspace = true } 5 | authors = { workspace = true } 6 | edition = { workspace = true } 7 | license = { workspace = true } 8 | repository = { workspace = true } 9 | description = "GeoArrow geometry type and metadata definitions." 10 | categories = { workspace = true } 11 | rust-version = { workspace = true } 12 | 13 | 14 | [dependencies] 15 | arrow-schema = { workspace = true } 16 | geo-traits = { workspace = true } 17 | serde = { workspace = true, features = ["derive"] } 18 | serde_json = { workspace = true } 19 | thiserror = { workspace = true } 20 | -------------------------------------------------------------------------------- /rust/geoarrow-schema/README.md: -------------------------------------------------------------------------------- 1 | # geoarrow-schema 2 | 3 | GeoArrow geometry type and metadata definitions. 4 | 5 | All geometry type definitions, such as [`PointType`], [`GeometryType`], or 6 | [`WkbType`] implement the upstream 7 | [`ExtensionType`][arrow_schema::extension::ExtensionType] trait. 8 | 9 | Instances of type definitions are included within the variants on the 10 | [`GeoArrowType`] enum. 11 | -------------------------------------------------------------------------------- /rust/geoarrow-schema/src/coord_type.rs: -------------------------------------------------------------------------------- 1 | /// The permitted GeoArrow coordinate representations. 2 | /// 3 | /// GeoArrow permits coordinate types to either be "Interleaved", where the X and Y coordinates are 4 | /// in a single buffer as `XYXYXY` or "Separated", where the X and Y coordinates are in multiple 5 | /// buffers as `XXXX` and `YYYY`. 6 | #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] 7 | pub enum CoordType { 8 | /// Interleaved coordinates. 9 | /// 10 | /// This stores coordinates in an Arrow 11 | /// [fixed-size-list-typed][arrow_schema::DataType::FixedSizeList] array. 12 | /// 13 | /// The size of the internal fixed-size list depends on the [dimension][crate::Dimension] of 14 | /// the array. 15 | /// 16 | /// ```notest 17 | /// FixedSizeList[n_dim] 18 | /// ``` 19 | Interleaved, 20 | 21 | /// Separated coordinates. 22 | /// 23 | /// This stores coordinates in an Arrow [struct-typed][arrow_schema::DataType::Struct] array: 24 | /// 25 | /// ```notest 26 | /// Struct]] 27 | /// ``` 28 | #[default] 29 | Separated, 30 | } 31 | -------------------------------------------------------------------------------- /rust/geoarrow-schema/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("../README.md")] 2 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 3 | #![warn(missing_docs)] 4 | 5 | mod coord_type; 6 | pub mod crs; 7 | mod datatype; 8 | mod dimension; 9 | mod edges; 10 | pub mod error; 11 | mod metadata; 12 | mod r#type; 13 | 14 | pub use coord_type::CoordType; 15 | pub use crs::{Crs, CrsType}; 16 | pub use datatype::GeoArrowType; 17 | pub use dimension::Dimension; 18 | pub use edges::Edges; 19 | pub use metadata::Metadata; 20 | pub use r#type::{ 21 | BoxType, GeometryCollectionType, GeometryType, LineStringType, MultiLineStringType, 22 | MultiPointType, MultiPolygonType, PointType, PolygonType, WkbType, WktType, 23 | }; 24 | -------------------------------------------------------------------------------- /rust/geoarrow-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geoarrow-test" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | license = { workspace = true } 7 | repository = { workspace = true } 8 | description = "Test data for GeoArrow data " 9 | categories = ["science::geo"] 10 | rust-version = { workspace = true } 11 | 12 | [dependencies] 13 | wkt = { workspace = true } 14 | -------------------------------------------------------------------------------- /rust/geoarrow-test/README.md: -------------------------------------------------------------------------------- 1 | # geoarrow-test 2 | 3 | Test data for geoarrow-rs. 4 | -------------------------------------------------------------------------------- /rust/geoarrow-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Test data for GeoArrow 2 | 3 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 4 | 5 | pub mod raw; 6 | -------------------------------------------------------------------------------- /rust/geoarrow-test/src/raw/mod.rs: -------------------------------------------------------------------------------- 1 | //! Raw test data, copied from geoarrow-data 2 | //! 3 | //! - 4 | //! - 5 | 6 | pub mod geometry; 7 | pub mod geometrycollection; 8 | pub mod linestring; 9 | pub mod multilinestring; 10 | pub mod multipoint; 11 | pub mod multipolygon; 12 | pub mod point; 13 | pub mod polygon; 14 | -------------------------------------------------------------------------------- /rust/geoarrow/benches/area.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, criterion_group, criterion_main}; 2 | use geoarrow::algorithm::geo::Area; 3 | use geoarrow::array::{AsChunkedNativeArray, MultiPolygonArray}; 4 | use geoarrow::io::flatgeobuf::FlatGeobufReaderBuilder; 5 | use geoarrow::table::Table; 6 | use std::fs::File; 7 | 8 | fn load_file() -> MultiPolygonArray { 9 | let file = File::open("fixtures/flatgeobuf/countries.fgb").unwrap(); 10 | let reader_builder = FlatGeobufReaderBuilder::open(file).unwrap(); 11 | let record_batch_reader = reader_builder.read(Default::default()).unwrap(); 12 | let table = 13 | Table::try_from(Box::new(record_batch_reader) as Box) 14 | .unwrap(); 15 | 16 | table 17 | .geometry_column(None) 18 | .unwrap() 19 | .as_ref() 20 | .as_multi_polygon() 21 | .chunks() 22 | .first() 23 | .unwrap() 24 | .clone() 25 | } 26 | 27 | fn criterion_benchmark(c: &mut Criterion) { 28 | let data = load_file(); 29 | 30 | c.bench_function("area", |bencher| { 31 | bencher.iter(|| { 32 | criterion::black_box(criterion::black_box(&data).signed_area()); 33 | }); 34 | }); 35 | } 36 | 37 | criterion_group!(benches, criterion_benchmark); 38 | criterion_main!(benches); 39 | -------------------------------------------------------------------------------- /rust/geoarrow/benches/from_geo.rs: -------------------------------------------------------------------------------- 1 | use geo::polygon; 2 | 3 | use criterion::{Criterion, criterion_group, criterion_main}; 4 | use geoarrow::array::{PolygonArray, PolygonBuilder}; 5 | use geoarrow_schema::{CoordType, Dimension}; 6 | 7 | fn create_data() -> Vec { 8 | // An L shape 9 | // https://github.com/georust/geo/blob/7cb7d0ffa6bf1544c5ca9922bd06100c36f815d7/README.md?plain=1#L40 10 | let poly = polygon![ 11 | (x: 0.0, y: 0.0), 12 | (x: 4.0, y: 0.0), 13 | (x: 4.0, y: 1.0), 14 | (x: 1.0, y: 1.0), 15 | (x: 1.0, y: 4.0), 16 | (x: 0.0, y: 4.0), 17 | (x: 0.0, y: 0.0), 18 | ]; 19 | let v = vec![poly; 1000]; 20 | v 21 | } 22 | 23 | pub fn criterion_benchmark(c: &mut Criterion) { 24 | let data = create_data(); 25 | 26 | c.bench_function("convert Vec to PolygonArray", |b| { 27 | b.iter(|| { 28 | let mut_arr = PolygonBuilder::from_polygons( 29 | &data, 30 | Dimension::XY, 31 | CoordType::default_interleaved(), 32 | Default::default(), 33 | ); 34 | let _arr: PolygonArray = mut_arr.into(); 35 | }) 36 | }); 37 | } 38 | 39 | criterion_group!(benches, criterion_benchmark); 40 | criterion_main!(benches); 41 | -------------------------------------------------------------------------------- /rust/geoarrow/benches/geos_buffer.rs: -------------------------------------------------------------------------------- 1 | use criterion::{Criterion, criterion_group, criterion_main}; 2 | use geoarrow::algorithm::geos::Buffer; 3 | use geoarrow::array::{CoordBuffer, InterleavedCoordBuffer, PointArray, PolygonArray}; 4 | use geoarrow_schema::Dimension; 5 | 6 | fn generate_data() -> PointArray { 7 | let coords = vec![0.0; 100_000]; 8 | let coord_buffer = 9 | CoordBuffer::Interleaved(InterleavedCoordBuffer::new(coords.into(), Dimension::XY)); 10 | PointArray::new(coord_buffer, None, Default::default()) 11 | } 12 | 13 | pub fn criterion_benchmark(c: &mut Criterion) { 14 | let point_array = generate_data(); 15 | 16 | c.bench_function("buffer", |b| { 17 | b.iter(|| { 18 | let _buffered: PolygonArray = point_array.buffer(1.0, 8).unwrap(); 19 | }) 20 | }); 21 | } 22 | 23 | criterion_group! { 24 | name = benches; 25 | config = Criterion::default().sample_size(10); 26 | targets = criterion_benchmark 27 | } 28 | criterion_main!(benches); 29 | -------------------------------------------------------------------------------- /rust/geoarrow/benches/translate.rs: -------------------------------------------------------------------------------- 1 | use geo::polygon; 2 | 3 | use criterion::{Criterion, criterion_group, criterion_main}; 4 | use geoarrow::algorithm::geo::Translate; 5 | use geoarrow::array::PolygonArray; 6 | use geoarrow_schema::Dimension; 7 | 8 | fn create_data() -> PolygonArray { 9 | // An L shape 10 | // https://github.com/georust/geo/blob/7cb7d0ffa6bf1544c5ca9922bd06100c36f815d7/README.md?plain=1#L40 11 | let poly = polygon![ 12 | (x: 0.0, y: 0.0), 13 | (x: 4.0, y: 0.0), 14 | (x: 4.0, y: 1.0), 15 | (x: 1.0, y: 1.0), 16 | (x: 1.0, y: 4.0), 17 | (x: 0.0, y: 4.0), 18 | (x: 0.0, y: 0.0), 19 | ]; 20 | let v = vec![poly; 1000]; 21 | (v.as_slice(), Dimension::XY).into() 22 | } 23 | 24 | pub fn criterion_benchmark(c: &mut Criterion) { 25 | let data = create_data(); 26 | 27 | c.bench_function("translate PolygonArray", |b| { 28 | b.iter(|| { 29 | let _ = data.translate(&10.0.into(), &20.0.into()); 30 | }) 31 | }); 32 | } 33 | 34 | criterion_group!(benches, criterion_benchmark); 35 | criterion_main!(benches); 36 | -------------------------------------------------------------------------------- /rust/geoarrow/examples/README.md: -------------------------------------------------------------------------------- 1 | # Rust Examples 2 | 3 | ## Usage with GDAL Arrow API 4 | 5 | As of GDAL version 3.6, GDAL has included support for [reading data into Arrow 6 | directly](https://gdal.org/development/rfc/rfc86_column_oriented_api.html). The file 7 | [`gdal.rs`](gdal.rs) shows how to use this API to efficiently load data into GeoArrow memory. 8 | 9 | Run with 10 | 11 | ```bash 12 | cargo run --example gdal --features gdal 13 | ``` 14 | -------------------------------------------------------------------------------- /rust/geoarrow/examples/gdal.rs: -------------------------------------------------------------------------------- 1 | use gdal::Dataset; 2 | use geoarrow::error::GeoArrowError; 3 | use geoarrow::io::gdal::read_gdal; 4 | use geoarrow::table::Table; 5 | use std::path::Path; 6 | 7 | fn run() -> Result<(), GeoArrowError> { 8 | // Open a dataset and access a layer 9 | let dataset = Dataset::open(Path::new("fixtures/roads.geojson"))?; 10 | let mut layer = dataset.layer(0)?; 11 | 12 | let reader = read_gdal(&mut layer, None)?; 13 | let table: Table = reader.try_into()?; 14 | dbg!(&table.schema()); 15 | 16 | Ok(()) 17 | } 18 | 19 | fn main() { 20 | run().unwrap() 21 | } 22 | -------------------------------------------------------------------------------- /rust/geoarrow/fixtures: -------------------------------------------------------------------------------- 1 | ../../fixtures -------------------------------------------------------------------------------- /rust/geoarrow/src/algorithm/geo/utils.rs: -------------------------------------------------------------------------------- 1 | use arrow_array::Float64Array; 2 | use arrow_buffer::NullBuffer; 3 | 4 | pub(crate) fn zeroes(len: usize, nulls: Option<&NullBuffer>) -> Float64Array { 5 | let values = vec![0.0f64; len]; 6 | Float64Array::new(values.into(), nulls.cloned()) 7 | } 8 | -------------------------------------------------------------------------------- /rust/geoarrow/src/algorithm/geo_index/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod rtree; 2 | 3 | pub use rtree::RTree; 4 | -------------------------------------------------------------------------------- /rust/geoarrow/src/algorithm/geodesy/mod.rs: -------------------------------------------------------------------------------- 1 | //! Bindings to the [`geodesy`] crate for coordinate reprojection. 2 | //! 3 | //! Note that this library does **not** aim to be a full PROJ "rewrite in Rust". Consult the 4 | //! [library's documentation][geodesy] for how to construct the projection string to pass into 5 | //! `reproject`. 6 | 7 | // TODO: reimplement not based on old GeometryArray enum 8 | // mod reproject; 9 | 10 | // pub use geodesy::Direction; 11 | // pub use reproject::reproject; 12 | -------------------------------------------------------------------------------- /rust/geoarrow/src/algorithm/geos/mod.rs: -------------------------------------------------------------------------------- 1 | //! Bindings to the [`geos`] crate for geometry operations. 2 | 3 | mod area; 4 | mod bool_ops; 5 | mod buffer; 6 | mod is_empty; 7 | mod is_ring; 8 | mod is_simple; 9 | mod is_valid; 10 | mod length; 11 | mod util; 12 | 13 | pub use area::Area; 14 | pub use bool_ops::{BooleanOps, BooleanOpsScalar}; 15 | pub use buffer::Buffer; 16 | pub use is_empty::IsEmpty; 17 | pub use is_ring::IsRing; 18 | pub use is_simple::IsSimple; 19 | pub use is_valid::IsValid; 20 | pub use length::Length; 21 | -------------------------------------------------------------------------------- /rust/geoarrow/src/algorithm/mod.rs: -------------------------------------------------------------------------------- 1 | //! Vectorized algorithms implemented on and returning GeoArrow arrays. 2 | 3 | #![allow(missing_docs)] // FIXME 4 | 5 | pub mod broadcasting; 6 | pub mod geo; 7 | pub mod geo_index; 8 | #[cfg(feature = "geos")] 9 | pub mod geos; 10 | pub mod native; 11 | #[cfg(feature = "polylabel")] 12 | pub mod polylabel; 13 | #[cfg(feature = "proj")] 14 | pub mod proj; 15 | pub mod rstar; 16 | -------------------------------------------------------------------------------- /rust/geoarrow/src/algorithm/native/mod.rs: -------------------------------------------------------------------------------- 1 | //! Operations that are implemented natively in this crate. 2 | //! 3 | //! Where possible, operations on scalars are implemented in terms of [geometry 4 | //! traits](../../geo_traits). 5 | 6 | mod binary; 7 | pub mod bounding_rect; 8 | mod cast; 9 | mod concatenate; 10 | pub(crate) mod downcast; 11 | pub(crate) mod eq; 12 | mod explode; 13 | mod map_chunks; 14 | mod map_coords; 15 | mod rechunk; 16 | mod take; 17 | mod total_bounds; 18 | pub(crate) mod type_id; 19 | mod unary; 20 | 21 | pub use binary::Binary; 22 | pub use bounding_rect::BoundingRectArray; 23 | pub use cast::Cast; 24 | pub use concatenate::Concatenate; 25 | pub use downcast::{Downcast, DowncastTable}; 26 | pub use explode::{Explode, ExplodeTable}; 27 | pub use map_chunks::MapChunks; 28 | pub use map_coords::MapCoords; 29 | pub use rechunk::Rechunk; 30 | pub use take::Take; 31 | pub use total_bounds::TotalBounds; 32 | pub use type_id::TypeIds; 33 | pub use unary::{Unary, UnaryPoint}; 34 | -------------------------------------------------------------------------------- /rust/geoarrow/src/indexed/mod.rs: -------------------------------------------------------------------------------- 1 | //! Indexed geometry arrays are associated with a spatial index for efficient 2 | //! boolean operations. 3 | 4 | #![allow(missing_docs)] // FIXME 5 | 6 | pub mod array; 7 | pub mod chunked; 8 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/display/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod array; 2 | pub mod chunked_array; 3 | pub mod scalar; 4 | pub mod table; 5 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/display/table.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | use crate::table::Table; 4 | 5 | impl fmt::Display for Table { 6 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 7 | writeln!(f, "Table")?; 8 | for field in self.schema().fields() { 9 | writeln!(f, "{}: {}", field.name(), field.data_type())?; 10 | } 11 | Ok(()) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/flatgeobuf/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read from and write to [FlatGeobuf](https://flatgeobuf.org/) files. 2 | 3 | mod reader; 4 | 5 | pub use reader::{FlatGeobufReader, FlatGeobufReaderBuilder, FlatGeobufReaderOptions}; 6 | #[cfg(feature = "flatgeobuf_async")] 7 | pub use reader::{FlatGeobufStream, FlatGeobufStreamBuilder, read_flatgeobuf_async}; 8 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/flatgeobuf/reader/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "flatgeobuf_async")] 2 | mod r#async; 3 | mod common; 4 | #[cfg(feature = "flatgeobuf_async")] 5 | mod object_store_reader; 6 | mod sync; 7 | 8 | #[cfg(feature = "flatgeobuf_async")] 9 | pub use r#async::{FlatGeobufStream, FlatGeobufStreamBuilder, read_flatgeobuf_async}; 10 | pub use common::FlatGeobufReaderOptions; 11 | pub use sync::{FlatGeobufReader, FlatGeobufReaderBuilder}; 12 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/gdal/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read-only integration with [GDAL][gdal]. 2 | 3 | mod reader; 4 | 5 | pub use reader::read_gdal; 6 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geojson/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read from and write to [GeoJSON](https://geojson.org/) files. 2 | 3 | pub use reader::read_geojson; 4 | pub use writer::write_geojson; 5 | 6 | mod reader; 7 | mod writer; 8 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geojson/writer.rs: -------------------------------------------------------------------------------- 1 | use crate::error::Result; 2 | use crate::io::stream::RecordBatchReader; 3 | use geozero::GeozeroDatasource; 4 | use geozero::geojson::GeoJsonWriter; 5 | use std::io::Write; 6 | 7 | /// Write a Table to GeoJSON 8 | /// 9 | /// Note: Does not reproject to WGS84 for you 10 | pub fn write_geojson>(stream: S, writer: W) -> Result<()> { 11 | let mut geojson = GeoJsonWriter::new(writer); 12 | stream.into().process(&mut geojson)?; 13 | Ok(()) 14 | } 15 | 16 | #[cfg(test)] 17 | mod test { 18 | use super::*; 19 | use crate::test::point; 20 | use std::io::BufWriter; 21 | 22 | #[test] 23 | fn test_write() { 24 | let table = point::table(); 25 | 26 | let mut output_buffer = Vec::new(); 27 | let writer = BufWriter::new(&mut output_buffer); 28 | write_geojson(&table, writer).unwrap(); 29 | let output_string = String::from_utf8(output_buffer).unwrap(); 30 | println!("{}", output_string); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geojson_lines/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read from and write to [newline-delimited GeoJSON](https://stevage.github.io/ndgeojson/) files. 2 | 3 | mod reader; 4 | mod writer; 5 | 6 | pub use reader::read_geojson_lines; 7 | pub use writer::write_geojson_lines; 8 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geojson_lines/reader.rs: -------------------------------------------------------------------------------- 1 | use std::io::BufRead; 2 | 3 | use geoarrow_schema::{CoordType, Dimension}; 4 | use geozero::GeozeroDatasource; 5 | use geozero::geojson::GeoJsonLineReader; 6 | 7 | use crate::error::Result; 8 | use crate::io::geozero::array::GeometryStreamBuilder; 9 | use crate::io::geozero::table::{GeoTableBuilder, GeoTableBuilderOptions}; 10 | use crate::table::Table; 11 | 12 | /// Read a GeoJSON Lines file 13 | /// 14 | /// This expects a GeoJSON Feature on each line of a text file, with a newline character separating 15 | /// each Feature. 16 | pub fn read_geojson_lines(reader: R, batch_size: Option) -> Result { 17 | let mut geojson_line_reader = GeoJsonLineReader::new(reader); 18 | 19 | // TODO: set crs to epsg:4326? 20 | let options = GeoTableBuilderOptions::new( 21 | CoordType::Interleaved, 22 | true, 23 | batch_size, 24 | None, 25 | None, 26 | Default::default(), 27 | ); 28 | let mut geo_table = 29 | GeoTableBuilder::::new_with_options(Dimension::XY, options); 30 | geojson_line_reader.process(&mut geo_table)?; 31 | geo_table.finish() 32 | } 33 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geojson_lines/writer.rs: -------------------------------------------------------------------------------- 1 | use geozero::GeozeroDatasource; 2 | use geozero::geojson::GeoJsonLineWriter; 3 | use std::io::Write; 4 | 5 | use crate::error::Result; 6 | use crate::io::stream::RecordBatchReader; 7 | 8 | /// Write a table to newline-delimited GeoJSON 9 | pub fn write_geojson_lines>( 10 | stream: S, 11 | writer: W, 12 | ) -> Result<()> { 13 | let mut geojson_writer = GeoJsonLineWriter::new(writer); 14 | stream.into().process(&mut geojson_writer)?; 15 | Ok(()) 16 | } 17 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/array/binary.rs: -------------------------------------------------------------------------------- 1 | use arrow::array::GenericBinaryBuilder; 2 | use arrow_array::OffsetSizeTrait; 3 | use geos::Geom; 4 | 5 | use crate::array::WKBArray; 6 | use crate::error::Result; 7 | 8 | impl WKBArray { 9 | #[allow(dead_code)] 10 | pub(crate) fn from_geos(value: Vec>) -> Result { 11 | let mut builder = GenericBinaryBuilder::new(); 12 | for maybe_geom in value { 13 | if let Some(geom) = maybe_geom { 14 | let buf = geom.to_wkb()?; 15 | builder.append_value(buf); 16 | } else { 17 | builder.append_null(); 18 | } 19 | } 20 | 21 | Ok(WKBArray::new(builder.finish(), Default::default())) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/array/geometrycollection.rs: -------------------------------------------------------------------------------- 1 | use crate::array::{GeometryCollectionArray, GeometryCollectionBuilder}; 2 | use crate::error::GeoArrowError; 3 | use crate::io::geos::scalar::GEOSGeometryCollection; 4 | use geoarrow_schema::{CoordType, Dimension}; 5 | 6 | impl TryFrom<(Vec, Dimension)> for GeometryCollectionBuilder { 7 | type Error = GeoArrowError; 8 | 9 | fn try_from( 10 | (value, dim): (Vec, Dimension), 11 | ) -> std::result::Result { 12 | let geoms: Vec = value 13 | .into_iter() 14 | .map(GEOSGeometryCollection::new_unchecked) 15 | .collect(); 16 | Self::from_geometry_collections( 17 | &geoms, 18 | dim, 19 | CoordType::Interleaved, 20 | Default::default(), 21 | false, 22 | ) 23 | } 24 | } 25 | 26 | impl TryFrom<(Vec, Dimension)> for GeometryCollectionArray { 27 | type Error = GeoArrowError; 28 | 29 | fn try_from(value: (Vec, Dimension)) -> std::result::Result { 30 | let mutable_arr: GeometryCollectionBuilder = value.try_into()?; 31 | Ok(mutable_arr.into()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/array/mixed.rs: -------------------------------------------------------------------------------- 1 | use crate::array::{MixedGeometryArray, MixedGeometryBuilder}; 2 | use crate::error::GeoArrowError; 3 | use crate::io::geos::scalar::GEOSGeometry; 4 | use geoarrow_schema::{CoordType, Dimension}; 5 | 6 | impl TryFrom<(Vec, Dimension)> for MixedGeometryBuilder { 7 | type Error = GeoArrowError; 8 | 9 | fn try_from( 10 | (value, dim): (Vec, Dimension), 11 | ) -> std::result::Result { 12 | let geoms: Vec = value.into_iter().map(GEOSGeometry::new).collect(); 13 | Self::from_geometries( 14 | &geoms, 15 | dim, 16 | CoordType::Interleaved, 17 | Default::default(), 18 | false, 19 | ) 20 | } 21 | } 22 | 23 | impl TryFrom<(Vec, Dimension)> for MixedGeometryArray { 24 | type Error = GeoArrowError; 25 | 26 | fn try_from(value: (Vec, Dimension)) -> std::result::Result { 27 | let mutable_arr: MixedGeometryBuilder = value.try_into()?; 28 | Ok(mutable_arr.into()) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/array/mod.rs: -------------------------------------------------------------------------------- 1 | mod binary; 2 | mod geometrycollection; 3 | mod linestring; 4 | mod mixed; 5 | mod multilinestring; 6 | mod multipoint; 7 | mod multipolygon; 8 | mod point; 9 | mod polygon; 10 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/mod.rs: -------------------------------------------------------------------------------- 1 | //! Export to and import from data structures of the [`geos`] crate. 2 | 3 | mod array; 4 | pub(crate) mod scalar; 5 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/scalar/binary.rs: -------------------------------------------------------------------------------- 1 | use crate::scalar::WKB; 2 | use arrow_array::OffsetSizeTrait; 3 | 4 | impl<'a, O: OffsetSizeTrait> TryFrom<&'a WKB<'_, O>> for geos::Geometry { 5 | type Error = geos::Error; 6 | 7 | fn try_from(value: &'a WKB<'_, O>) -> std::result::Result { 8 | geos::Geometry::new_from_wkb(value.arr.value(value.geom_index)) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/scalar/coord/interleaved.rs: -------------------------------------------------------------------------------- 1 | use crate::array::InterleavedCoordBuffer; 2 | use geoarrow_schema::Dimension; 3 | use geos::CoordSeq; 4 | 5 | impl TryFrom for CoordSeq { 6 | type Error = geos::Error; 7 | 8 | fn try_from(value: InterleavedCoordBuffer) -> std::result::Result { 9 | match value.dim { 10 | Dimension::XY => CoordSeq::new_from_buffer(&value.coords, value.len(), false, false), 11 | Dimension::XYZ => CoordSeq::new_from_buffer(&value.coords, value.len(), true, false), 12 | _ => todo!("XYM and XYZM not supported yet"), 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/scalar/coord/separated.rs: -------------------------------------------------------------------------------- 1 | use crate::array::SeparatedCoordBuffer; 2 | use geoarrow_schema::Dimension; 3 | use geos::CoordSeq; 4 | 5 | impl TryFrom for CoordSeq { 6 | type Error = geos::Error; 7 | 8 | fn try_from(value: SeparatedCoordBuffer) -> std::result::Result { 9 | match value.dim { 10 | Dimension::XY => { 11 | CoordSeq::new_from_arrays(&value.buffers[0], &value.buffers[1], None, None) 12 | } 13 | Dimension::XYZ => CoordSeq::new_from_arrays( 14 | &value.buffers[0], 15 | &value.buffers[1], 16 | Some(&value.buffers[2]), 17 | None, 18 | ), 19 | _ => todo!("XYM and XYZM not supported yet"), 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geos/scalar/mod.rs: -------------------------------------------------------------------------------- 1 | mod binary; 2 | mod coord; 3 | mod geometry; 4 | mod geometrycollection; 5 | mod linearring; 6 | mod linestring; 7 | mod multilinestring; 8 | mod multipoint; 9 | mod multipolygon; 10 | mod point; 11 | mod polygon; 12 | 13 | pub use geometry::GEOSGeometry; 14 | pub(crate) use geometry::to_geos_geometry; 15 | pub use geometrycollection::GEOSGeometryCollection; 16 | pub use linearring::GEOSConstLinearRing; 17 | pub use linestring::{GEOSConstLineString, GEOSLineString}; 18 | pub use multilinestring::GEOSMultiLineString; 19 | pub use multipoint::GEOSMultiPoint; 20 | pub use multipolygon::GEOSMultiPolygon; 21 | pub use point::{GEOSConstPoint, GEOSPoint}; 22 | pub use polygon::{GEOSConstPolygon, GEOSPolygon}; 23 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/array/geometrycollection.rs: -------------------------------------------------------------------------------- 1 | use crate::ArrayBase; 2 | use crate::array::GeometryCollectionArray; 3 | use crate::io::geozero::scalar::process_geometry_collection; 4 | use crate::trait_::ArrayAccessor; 5 | use geozero::{GeomProcessor, GeozeroGeometry}; 6 | 7 | impl GeozeroGeometry for GeometryCollectionArray { 8 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 9 | where 10 | Self: Sized, 11 | { 12 | let num_geometries = self.len(); 13 | processor.geometrycollection_begin(num_geometries, 0)?; 14 | 15 | for geom_idx in 0..num_geometries { 16 | process_geometry_collection(&self.value(geom_idx), geom_idx, processor)?; 17 | } 18 | 19 | processor.geometrycollection_end(num_geometries - 1)?; 20 | Ok(()) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/array/mod.rs: -------------------------------------------------------------------------------- 1 | mod dynamic; 2 | mod geometry; 3 | mod geometrycollection; 4 | mod linestring; 5 | mod multilinestring; 6 | mod multipoint; 7 | mod multipolygon; 8 | mod point; 9 | mod polygon; 10 | 11 | pub use geometry::{GeometryStreamBuilder, ToGeometryArray}; 12 | pub use linestring::ToLineStringArray; 13 | pub use multilinestring::ToMultiLineStringArray; 14 | pub use multipoint::ToMultiPointArray; 15 | pub use multipolygon::ToMultiPolygonArray; 16 | pub use point::ToPointArray; 17 | pub use polygon::ToPolygonArray; 18 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/mod.rs: -------------------------------------------------------------------------------- 1 | //! Implements the geometry and dataset conversion APIs defined by the [`geozero`] 2 | //! crate. 3 | 4 | pub(crate) mod array; 5 | mod scalar; 6 | pub(crate) mod table; 7 | 8 | pub use array::{ 9 | ToGeometryArray, ToLineStringArray, ToMultiLineStringArray, ToMultiPointArray, 10 | ToMultiPolygonArray, ToPointArray, ToPolygonArray, 11 | }; 12 | pub use scalar::ToGeometry; 13 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/binary.rs: -------------------------------------------------------------------------------- 1 | use std::io::Cursor; 2 | 3 | use arrow_array::OffsetSizeTrait; 4 | use geozero::wkb::process_wkb_geom; 5 | use geozero::{GeomProcessor, GeozeroGeometry}; 6 | 7 | use crate::scalar::WKB; 8 | 9 | impl GeozeroGeometry for WKB<'_, O> { 10 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 11 | where 12 | Self: Sized, 13 | { 14 | let slice = self.arr.value(self.geom_index); 15 | process_wkb_geom(&mut Cursor::new(slice), processor) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/geometry_collection.rs: -------------------------------------------------------------------------------- 1 | use crate::io::geozero::scalar::geometry::process_geometry; 2 | use crate::scalar::GeometryCollection; 3 | use geo_traits::GeometryCollectionTrait; 4 | use geozero::{GeomProcessor, GeozeroGeometry}; 5 | 6 | pub(crate) fn process_geometry_collection( 7 | geom: &impl GeometryCollectionTrait, 8 | geom_idx: usize, 9 | processor: &mut P, 10 | ) -> geozero::error::Result<()> { 11 | processor.geometrycollection_begin(geom.num_geometries(), geom_idx)?; 12 | 13 | for (i, geometry) in geom.geometries().enumerate() { 14 | process_geometry(&geometry, i, processor)?; 15 | } 16 | 17 | processor.geometrycollection_end(geom_idx)?; 18 | Ok(()) 19 | } 20 | 21 | impl GeozeroGeometry for GeometryCollection<'_> { 22 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 23 | where 24 | Self: Sized, 25 | { 26 | process_geometry_collection(&self, 0, processor) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/linestring.rs: -------------------------------------------------------------------------------- 1 | use crate::io::geozero::scalar::process_coord; 2 | use crate::scalar::LineString; 3 | use geo_traits::LineStringTrait; 4 | use geozero::{GeomProcessor, GeozeroGeometry}; 5 | 6 | pub(crate) fn process_line_string( 7 | geom: &impl LineStringTrait, 8 | geom_idx: usize, 9 | processor: &mut P, 10 | ) -> geozero::error::Result<()> { 11 | processor.linestring_begin(true, geom.num_coords(), geom_idx)?; 12 | 13 | for (coord_idx, coord) in geom.coords().enumerate() { 14 | process_coord(&coord, coord_idx, processor)?; 15 | } 16 | 17 | processor.linestring_end(true, geom_idx)?; 18 | Ok(()) 19 | } 20 | 21 | impl GeozeroGeometry for LineString<'_> { 22 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 23 | where 24 | Self: Sized, 25 | { 26 | process_line_string(self, 0, processor) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/mod.rs: -------------------------------------------------------------------------------- 1 | mod binary; 2 | mod coord; 3 | mod geometry; 4 | mod geometry_array; 5 | mod geometry_collection; 6 | mod linestring; 7 | mod multilinestring; 8 | mod multipoint; 9 | mod multipolygon; 10 | mod point; 11 | mod polygon; 12 | 13 | pub(crate) use coord::process_coord; 14 | pub(crate) use geometry::process_geometry; 15 | pub(crate) use geometry_collection::process_geometry_collection; 16 | pub(crate) use linestring::process_line_string; 17 | pub(crate) use multilinestring::process_multi_line_string; 18 | pub(crate) use multipoint::process_multi_point; 19 | pub(crate) use multipolygon::process_multi_polygon; 20 | pub(crate) use point::{process_point, process_point_as_coord}; 21 | pub(crate) use polygon::process_polygon; 22 | 23 | pub use geometry::ToGeometry; 24 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/multilinestring.rs: -------------------------------------------------------------------------------- 1 | use crate::io::geozero::scalar::process_coord; 2 | use crate::scalar::MultiLineString; 3 | use geo_traits::{LineStringTrait, MultiLineStringTrait}; 4 | use geozero::{GeomProcessor, GeozeroGeometry}; 5 | 6 | pub(crate) fn process_multi_line_string( 7 | geom: &impl MultiLineStringTrait, 8 | geom_idx: usize, 9 | processor: &mut P, 10 | ) -> geozero::error::Result<()> { 11 | processor.multilinestring_begin(geom.num_line_strings(), geom_idx)?; 12 | 13 | for (line_idx, line) in geom.line_strings().enumerate() { 14 | processor.linestring_begin(false, line.num_coords(), line_idx)?; 15 | 16 | for (coord_idx, coord) in line.coords().enumerate() { 17 | process_coord(&coord, coord_idx, processor)?; 18 | } 19 | 20 | processor.linestring_end(false, line_idx)?; 21 | } 22 | 23 | processor.multilinestring_end(geom_idx)?; 24 | Ok(()) 25 | } 26 | 27 | impl GeozeroGeometry for MultiLineString<'_> { 28 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 29 | where 30 | Self: Sized, 31 | { 32 | process_multi_line_string(self, 0, processor) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/multipoint.rs: -------------------------------------------------------------------------------- 1 | use crate::io::geozero::scalar::process_point_as_coord; 2 | use crate::scalar::MultiPoint; 3 | use geo_traits::MultiPointTrait; 4 | use geozero::{GeomProcessor, GeozeroGeometry}; 5 | 6 | pub(crate) fn process_multi_point( 7 | geom: &impl MultiPointTrait, 8 | geom_idx: usize, 9 | processor: &mut P, 10 | ) -> geozero::error::Result<()> { 11 | processor.multipoint_begin(geom.num_points(), geom_idx)?; 12 | 13 | for (point_idx, point) in geom.points().enumerate() { 14 | process_point_as_coord(&point, point_idx, processor)?; 15 | } 16 | 17 | processor.multipoint_end(geom_idx)?; 18 | Ok(()) 19 | } 20 | 21 | impl GeozeroGeometry for MultiPoint<'_> { 22 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 23 | where 24 | Self: Sized, 25 | { 26 | process_multi_point(self, 0, processor) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/scalar/multipolygon.rs: -------------------------------------------------------------------------------- 1 | use crate::io::geozero::scalar::polygon::process_polygon; 2 | use crate::scalar::MultiPolygon; 3 | use geo_traits::MultiPolygonTrait; 4 | use geozero::{GeomProcessor, GeozeroGeometry}; 5 | 6 | pub(crate) fn process_multi_polygon( 7 | geom: &impl MultiPolygonTrait, 8 | geom_idx: usize, 9 | processor: &mut P, 10 | ) -> geozero::error::Result<()> { 11 | processor.multipolygon_begin(geom.num_polygons(), geom_idx)?; 12 | 13 | for (polygon_idx, polygon) in geom.polygons().enumerate() { 14 | process_polygon(&polygon, false, polygon_idx, processor)?; 15 | } 16 | 17 | processor.multipolygon_end(geom_idx)?; 18 | Ok(()) 19 | } 20 | 21 | impl GeozeroGeometry for MultiPolygon<'_> { 22 | fn process_geom(&self, processor: &mut P) -> geozero::error::Result<()> 23 | where 24 | Self: Sized, 25 | { 26 | process_multi_polygon(self, 0, processor) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/table/builder/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod anyvalue; 2 | pub(crate) mod properties; 3 | mod table; 4 | 5 | pub use table::{GeoTableBuilder, GeoTableBuilderOptions}; 6 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/geozero/table/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod builder; 2 | mod data_source; 3 | mod json_encoder; 4 | 5 | pub use builder::{GeoTableBuilder, GeoTableBuilderOptions}; 6 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/ipc/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read from and write to [Arrow IPC](https://arrow.apache.org/docs/format/Columnar.html#format-ipc) files. 2 | 3 | mod reader; 4 | mod writer; 5 | 6 | pub use reader::{read_ipc, read_ipc_stream}; 7 | pub use writer::{write_ipc, write_ipc_stream}; 8 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/ipc/reader.rs: -------------------------------------------------------------------------------- 1 | use std::io::{Read, Seek}; 2 | 3 | use arrow_ipc::reader::{FileReader, StreamReader}; 4 | use arrow_schema::ArrowError; 5 | 6 | use crate::error::Result; 7 | use crate::table::Table; 8 | 9 | /// Read into a Table from Arrow IPC (Feather v2) file. 10 | pub fn read_ipc(reader: R) -> Result
{ 11 | let reader = FileReader::try_new(reader, None)?; 12 | let schema = reader.schema(); 13 | let batches = reader.collect::, ArrowError>>()?; 14 | Table::try_new(batches, schema) 15 | } 16 | 17 | /// Read into a Table from Arrow IPC record batch stream. 18 | pub fn read_ipc_stream(reader: R) -> Result
{ 19 | let reader = StreamReader::try_new(reader, None)?; 20 | let schema = reader.schema(); 21 | let batches = reader.collect::, ArrowError>>()?; 22 | Table::try_new(batches, schema) 23 | } 24 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/ipc/writer.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use arrow_ipc::writer::{FileWriter, StreamWriter}; 4 | 5 | use crate::error::Result; 6 | use crate::io::stream::RecordBatchReader; 7 | 8 | /// Write a Table to an Arrow IPC (Feather v2) file 9 | pub fn write_ipc>(stream: S, writer: W) -> Result<()> { 10 | let inner: RecordBatchReader = stream.into(); 11 | let inner = inner.into_inner(); 12 | 13 | let schema = inner.schema(); 14 | let mut writer = FileWriter::try_new(writer, &schema)?; 15 | for batch in inner { 16 | writer.write(&batch?)?; 17 | } 18 | writer.finish()?; 19 | Ok(()) 20 | } 21 | 22 | /// Write a Table to an Arrow IPC stream 23 | pub fn write_ipc_stream>(stream: S, writer: W) -> Result<()> { 24 | let inner: RecordBatchReader = stream.into(); 25 | let inner = inner.into_inner(); 26 | 27 | let schema = inner.schema(); 28 | let mut writer = StreamWriter::try_new(writer, &schema)?; 29 | for batch in inner { 30 | writer.write(&batch?)?; 31 | } 32 | writer.finish()?; 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Reader and writer implementations of many common geospatial file formats, including 2 | //! interoperability with the [`geozero`] crate. 3 | 4 | pub mod crs; 5 | #[cfg(feature = "csv")] 6 | pub mod csv; 7 | pub(crate) mod display; 8 | #[cfg(feature = "flatgeobuf")] 9 | pub mod flatgeobuf; 10 | #[cfg(feature = "gdal")] 11 | pub mod gdal; 12 | pub(crate) mod geo; 13 | pub mod geojson; 14 | pub mod geojson_lines; 15 | #[cfg(feature = "geos")] 16 | pub(crate) mod geos; 17 | pub mod geozero; 18 | pub mod ipc; 19 | #[cfg(feature = "postgis")] 20 | pub mod postgis; 21 | pub mod shapefile; 22 | mod stream; 23 | pub mod wkb; 24 | pub mod wkt; 25 | 26 | pub use stream::RecordBatchReader; 27 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/postgis/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read from PostGIS databases. 2 | 3 | mod reader; 4 | mod type_info; 5 | 6 | pub use reader::read_postgis; 7 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/shapefile/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read from [Shapefile](https://www.esri.com/content/dam/esrisites/sitecore-archive/Files/Pdfs/library/whitepapers/pdfs/shapefile.pdf) datasets. 2 | //! 3 | //! This wraps the [shapefile] crate. 4 | 5 | mod reader; 6 | mod scalar; 7 | 8 | pub use reader::{ShapefileReaderOptions, read_shapefile}; 9 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/wkb/mod.rs: -------------------------------------------------------------------------------- 1 | //! Read and write geometries encoded as [Well-Known Binary](https://libgeos.org/specifications/wkb/). 2 | //! 3 | //! This wraps the [wkb] crate. As such, it currently supports reading the ISO and extended (EWKB) 4 | //! variants of WKB. Currently, it always writes the ISO WKB variant. 5 | 6 | mod api; 7 | pub(crate) mod writer; 8 | 9 | pub use api::{FromWKB, ToWKB, from_wkb, to_wkb}; 10 | -------------------------------------------------------------------------------- /rust/geoarrow/src/io/wkb/writer/mod.rs: -------------------------------------------------------------------------------- 1 | mod geometry; 2 | mod geometrycollection; 3 | mod linestring; 4 | mod multilinestring; 5 | mod multipoint; 6 | mod multipolygon; 7 | mod point; 8 | mod polygon; 9 | mod rect; 10 | -------------------------------------------------------------------------------- /rust/geodatafusion/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "geodatafusion" 3 | version = "0.1.0-dev" 4 | authors = ["Kyle Barron "] 5 | edition = { workspace = true } 6 | license = { workspace = true } 7 | repository = { workspace = true } 8 | description = "Rust implementation of GeoArrow" 9 | categories = { workspace = true } 10 | rust-version = { workspace = true } 11 | 12 | 13 | [dependencies] 14 | arrow-array = { workspace = true } 15 | arrow-schema = { workspace = true } 16 | datafusion = { workspace = true } 17 | geoarrow-array = { workspace = true } 18 | geoarrow-schema = { workspace = true } 19 | geohash = { workspace = true } 20 | thiserror = { workspace = true } 21 | wkt = { workspace = true } 22 | 23 | [dev-dependencies] 24 | approx = { workspace = true } 25 | geo-traits = { workspace = true } 26 | geoarrow-array = { workspace = true, features = ["test-data"] } 27 | tokio = { workspace = true, features = ["macros", "fs", "rt-multi-thread"] } 28 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Defines [`GeoArrowError`], representing all errors returned by this crate. 2 | 3 | use std::fmt::Debug; 4 | 5 | use arrow_schema::ArrowError; 6 | use datafusion::error::DataFusionError; 7 | use geoarrow_schema::error::GeoArrowError; 8 | use thiserror::Error; 9 | 10 | /// Enum with all errors in this crate. 11 | #[derive(Error, Debug)] 12 | pub(crate) enum GeoDataFusionError { 13 | #[error(transparent)] 14 | Arrow(#[from] ArrowError), 15 | 16 | #[error(transparent)] 17 | DataFusion(#[from] DataFusionError), 18 | 19 | #[error(transparent)] 20 | GeoArrow(#[from] GeoArrowError), 21 | 22 | #[error(transparent)] 23 | GeoHash(#[from] geohash::GeohashError), 24 | } 25 | 26 | /// Crate-specific result type. 27 | pub(crate) type GeoDataFusionResult = std::result::Result; 28 | 29 | impl From for DataFusionError { 30 | fn from(value: GeoDataFusionError) -> Self { 31 | match value { 32 | GeoDataFusionError::Arrow(err) => DataFusionError::ArrowError(err, None), 33 | GeoDataFusionError::DataFusion(err) => err, 34 | GeoDataFusionError::GeoArrow(err) => DataFusionError::External(Box::new(err)), 35 | GeoDataFusionError::GeoHash(err) => DataFusionError::External(Box::new(err)), 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Temporary 2 | #![allow(dead_code)] 3 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 4 | 5 | pub(crate) mod data_types; 6 | pub(crate) mod error; 7 | pub mod udf; 8 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod native; 2 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/accessors/mod.rs: -------------------------------------------------------------------------------- 1 | mod coord_dim; 2 | mod envelope; 3 | mod line_string; 4 | 5 | use datafusion::prelude::SessionContext; 6 | 7 | /// Register all provided [geo] functions for constructing geometries 8 | pub fn register_udfs(ctx: &SessionContext) { 9 | ctx.register_udf(coord_dim::CoordDim::new().into()); 10 | ctx.register_udf(envelope::Envelope::new().into()); 11 | ctx.register_udf(line_string::StartPoint::new().into()); 12 | } 13 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/bounding_box/mod.rs: -------------------------------------------------------------------------------- 1 | mod box_2d; 2 | mod expand; 3 | mod extrema; 4 | mod make_box_2d; 5 | 6 | use datafusion::prelude::SessionContext; 7 | 8 | /// Register all provided bounding box functions 9 | pub fn register_udfs(ctx: &SessionContext) { 10 | ctx.register_udf(box_2d::Box2D::new().into()); 11 | ctx.register_udf(expand::Expand::new().into()); 12 | ctx.register_udf(extrema::XMax::new().into()); 13 | ctx.register_udf(extrema::XMin::new().into()); 14 | ctx.register_udf(extrema::YMax::new().into()); 15 | ctx.register_udf(extrema::YMin::new().into()); 16 | ctx.register_udf(make_box_2d::MakeBox2D::new().into()); 17 | } 18 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/constructors/mod.rs: -------------------------------------------------------------------------------- 1 | mod point; 2 | 3 | pub use point::{MakePoint, MakePointM, Point, PointM, PointZ, PointZM}; 4 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/io/mod.rs: -------------------------------------------------------------------------------- 1 | //! Geometry Input and Output 2 | 3 | // mod geohash; 4 | mod wkb; 5 | mod wkt; 6 | 7 | pub use wkb::{AsBinary, GeomFromWKB}; 8 | pub use wkt::{AsText, GeomFromText}; 9 | 10 | // use datafusion::prelude::SessionContext; 11 | 12 | // /// Register all provided functions for geometry input and output 13 | // pub fn register_udfs(ctx: &SessionContext) { 14 | // ctx.register_udf(geohash::Box2DFromGeoHash::new().into()); 15 | // ctx.register_udf(geohash::GeoHash::new().into()); 16 | // ctx.register_udf(geohash::PointFromGeoHash::new().into()); 17 | // ctx.register_udf(wkb::AsBinary::new().into()); 18 | // ctx.register_udf(wkb::GeomFromWKB::new().into()); 19 | // ctx.register_udf(wkt::AsText::new().into()); 20 | // ctx.register_udf(wkt::GeomFromText::new().into()); 21 | // } 22 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/measurement/mod.rs: -------------------------------------------------------------------------------- 1 | mod area; 2 | 3 | use datafusion::prelude::SessionContext; 4 | 5 | /// Register all provided [geo] functions for constructing geometries 6 | pub fn register_udfs(ctx: &SessionContext) { 7 | ctx.register_udf(area::Area::new().into()); 8 | } 9 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/mod.rs: -------------------------------------------------------------------------------- 1 | //! User-defined functions that wrap native Rust implementations. 2 | 3 | // mod accessors; 4 | // mod bounding_box; 5 | pub mod constructors; 6 | pub mod io; 7 | // mod measurement; 8 | // mod processing; 9 | 10 | // use datafusion::prelude::SessionContext; 11 | 12 | // /// Register all provided native-Rust functions 13 | // pub fn register_native(ctx: &SessionContext) { 14 | // accessors::register_udfs(ctx); 15 | // bounding_box::register_udfs(ctx); 16 | // constructors::register_udfs(ctx); 17 | // io::register_udfs(ctx); 18 | // measurement::register_udfs(ctx); 19 | // processing::register_udfs(ctx); 20 | // } 21 | -------------------------------------------------------------------------------- /rust/geodatafusion/src/udf/native/processing/mod.rs: -------------------------------------------------------------------------------- 1 | mod centroid; 2 | mod chaikin_smoothing; 3 | mod concave_hull; 4 | mod convex_hull; 5 | mod point_on_surface; 6 | mod simplify; 7 | mod simplify_preserve_topology; 8 | mod simplify_vw; 9 | 10 | use datafusion::prelude::SessionContext; 11 | 12 | /// Register all provided [geo] functions for processing geometries 13 | pub fn register_udfs(ctx: &SessionContext) { 14 | ctx.register_udf(centroid::Centroid::new().into()); 15 | ctx.register_udf(concave_hull::ConcaveHull::new().into()); 16 | ctx.register_udf(convex_hull::ConvexHull::new().into()); 17 | ctx.register_udf(point_on_surface::PointOnSurface::new().into()); 18 | ctx.register_udf(simplify_preserve_topology::SimplifyPreserveTopology::new().into()); 19 | ctx.register_udf(simplify_vw::SimplifyVw::new().into()); 20 | ctx.register_udf(simplify::Simplify::new().into()); 21 | } 22 | -------------------------------------------------------------------------------- /rust/geoparquet/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "geoparquet" 4 | version = { workspace = true } 5 | authors = { workspace = true } 6 | edition = { workspace = true } 7 | license = { workspace = true } 8 | repository = { workspace = true } 9 | description = "GeoParquet reader and writer." 10 | categories = { workspace = true } 11 | rust-version = { workspace = true } 12 | 13 | 14 | [features] 15 | async = ["parquet/async", "dep:futures"] 16 | compression = [ 17 | "parquet/snap", 18 | "parquet/brotli", 19 | "parquet/flate2", 20 | "parquet/lz4", 21 | "parquet/zstd", 22 | ] 23 | 24 | [dependencies] 25 | arrow-arith = { workspace = true } 26 | arrow-array = { workspace = true } 27 | arrow-buffer = { workspace = true } 28 | arrow-ord = { workspace = true } 29 | arrow-schema = { workspace = true } 30 | futures = { workspace = true, optional = true } 31 | geo-traits = { workspace = true } 32 | geo-types = { workspace = true } 33 | geoarrow-array = { workspace = true } 34 | geoarrow-schema = { workspace = true } 35 | indexmap = { workspace = true } 36 | parquet = { workspace = true, features = ["arrow"] } 37 | serde = { workspace = true, features = ["derive"] } 38 | serde_with = { workspace = true } 39 | serde_json = { workspace = true } 40 | 41 | [dev-dependencies] 42 | tokio = { version = "1.9", features = ["macros", "fs", "rt-multi-thread"] } 43 | tokio-test = "0.4" 44 | -------------------------------------------------------------------------------- /rust/geoparquet/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/rust/geoparquet/README.md -------------------------------------------------------------------------------- /rust/geoparquet/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Read and write the [GeoParquet](https://github.com/opengeospatial/geoparquet) format. 2 | 3 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 4 | #![warn(missing_docs)] 5 | 6 | pub mod metadata; 7 | pub mod reader; 8 | #[cfg(test)] 9 | mod test; 10 | mod total_bounds; 11 | pub mod writer; 12 | -------------------------------------------------------------------------------- /rust/geoparquet/src/reader/mod.rs: -------------------------------------------------------------------------------- 1 | #![doc = include_str!("README.md")] 2 | 3 | #[cfg(feature = "async")] 4 | mod r#async; 5 | mod geo_ext; 6 | mod metadata; 7 | mod parse; 8 | mod spatial_filter; 9 | mod sync; 10 | 11 | #[cfg(feature = "async")] 12 | pub use r#async::GeoParquetRecordBatchStream; 13 | pub use geo_ext::GeoParquetReaderBuilder; 14 | pub use metadata::{GeoParquetDatasetMetadata, GeoParquetReaderMetadata}; 15 | pub use sync::GeoParquetRecordBatchReader; 16 | -------------------------------------------------------------------------------- /rust/geoparquet/src/test/geoarrow_data/mod.rs: -------------------------------------------------------------------------------- 1 | mod example; 2 | mod example_crs; 3 | -------------------------------------------------------------------------------- /rust/geoparquet/src/test/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "compression")] 2 | mod geoarrow_data; 3 | 4 | use std::path::PathBuf; 5 | 6 | pub(crate) fn fixture_dir() -> PathBuf { 7 | let p = PathBuf::from("../../fixtures"); 8 | assert!(p.exists()); 9 | p 10 | } 11 | 12 | pub(crate) fn geoarrow_data_example_files() -> PathBuf { 13 | fixture_dir().join("geoarrow-data/example/files") 14 | } 15 | 16 | pub(crate) fn geoarrow_data_example_crs_files() -> PathBuf { 17 | fixture_dir().join("geoarrow-data/example-crs/files") 18 | } 19 | -------------------------------------------------------------------------------- /rust/geoparquet/src/writer/mod.rs: -------------------------------------------------------------------------------- 1 | //! Write GeoArrow data to GeoParquet. 2 | 3 | #[cfg(feature = "async")] 4 | mod r#async; 5 | mod encode; 6 | mod metadata; 7 | mod options; 8 | mod sync; 9 | 10 | #[cfg(feature = "async")] 11 | pub use r#async::{GeoParquetWriterAsync, write_geoparquet_async}; 12 | pub use options::{GeoParquetWriterEncoding, GeoParquetWriterOptions}; 13 | pub use sync::{GeoParquetWriter, write_geoparquet}; 14 | -------------------------------------------------------------------------------- /rust/geoparquet/src/writer/options.rs: -------------------------------------------------------------------------------- 1 | use geoarrow_schema::crs::CrsTransform; 2 | use parquet::file::properties::WriterProperties; 3 | 4 | /// Allowed encodings when writing to GeoParquet 5 | #[derive(Copy, Clone, Default)] 6 | #[allow(clippy::upper_case_acronyms)] 7 | pub enum GeoParquetWriterEncoding { 8 | /// Well-known binary geometry encoding 9 | /// 10 | /// This is the only encoding supported in GeoParquet version 1.0, so if you wish to maintain 11 | /// compatibility with that version, you must choose WKB. 12 | #[default] 13 | WKB, 14 | 15 | /// GeoArrow-native encoding. This is supported as of GeoParquet version 1.1. 16 | Native, 17 | } 18 | 19 | /// Options for writing GeoParquet 20 | #[derive(Default)] 21 | pub struct GeoParquetWriterOptions { 22 | /// Set the type of encoding to use for writing to GeoParquet. 23 | pub encoding: GeoParquetWriterEncoding, 24 | 25 | /// Set the primary geometry column name. 26 | pub primary_column: Option, 27 | 28 | /// The parquet [WriterProperties] to use for writing to file 29 | pub writer_properties: Option, 30 | 31 | /// A transformer for converting CRS from the GeoArrow representation to PROJJSON. 32 | pub crs_transform: Option>, 33 | } 34 | -------------------------------------------------------------------------------- /rust/pyo3-geoarrow/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pyo3-geoarrow" 3 | version = { workspace = true } 4 | authors = { workspace = true } 5 | edition = { workspace = true } 6 | description = "GeoArrow integration for pyo3." 7 | readme = "README.md" 8 | repository = { workspace = true } 9 | license = { workspace = true } 10 | keywords = ["python", "arrow"] 11 | categories = [] 12 | rust-version = { workspace = true } 13 | 14 | [features] 15 | geozero = ["dep:geozero", "geoarrow-array/geozero"] 16 | 17 | [dependencies] 18 | arrow-array = { workspace = true } 19 | arrow-buffer = { workspace = true } 20 | arrow-cast = { workspace = true } 21 | arrow-schema = { workspace = true } 22 | geo-traits = { workspace = true } 23 | geo-types = { workspace = true } 24 | geoarrow-array = { workspace = true } 25 | geoarrow-cast = { workspace = true } 26 | geoarrow-schema = { workspace = true } 27 | geozero = { workspace = true, optional = true } 28 | pyo3 = { workspace = true, features = ["chrono", "indexmap"] } 29 | pyo3-arrow = { workspace = true } 30 | serde_json = { workspace = true } 31 | url = { workspace = true } 32 | 33 | [lib] 34 | crate-type = ["rlib"] 35 | -------------------------------------------------------------------------------- /rust/pyo3-geoarrow/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/geoarrow/geoarrow-rs/3e8c0e4c45c4f480381fef06922ba343e3c10bf2/rust/pyo3-geoarrow/README.md -------------------------------------------------------------------------------- /rust/pyo3-geoarrow/src/ffi/from_python/mod.rs: -------------------------------------------------------------------------------- 1 | // pub mod scalar; 2 | -------------------------------------------------------------------------------- /rust/pyo3-geoarrow/src/ffi/mod.rs: -------------------------------------------------------------------------------- 1 | //! Arrow FFI via the C Data Interface and the Arrow PyCapsule Interface. 2 | 3 | pub mod from_python; 4 | -------------------------------------------------------------------------------- /rust/pyo3-geoarrow/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 2 | 3 | mod array; 4 | mod array_reader; 5 | mod chunked_array; 6 | mod coord_buffer; 7 | mod coord_type; 8 | mod crs; 9 | pub mod data_type; 10 | mod dimension; 11 | mod edges; 12 | mod error; 13 | mod ffi; 14 | mod offset_buffer; 15 | mod scalar; 16 | 17 | pub use array::PyGeoArrowArray; 18 | pub use array_reader::PyGeoArrowArrayReader; 19 | pub use chunked_array::PyChunkedGeoArrowArray; 20 | pub use coord_buffer::PyCoordBuffer; 21 | pub use coord_type::PyCoordType; 22 | pub use crs::{PyCrs, PyprojCRSTransform}; 23 | pub use dimension::PyDimension; 24 | pub use edges::PyEdges; 25 | pub use error::{PyGeoArrowError, PyGeoArrowResult}; 26 | pub use offset_buffer::PyOffsetBuffer; 27 | pub use scalar::PyGeoArrowScalar; 28 | -------------------------------------------------------------------------------- /rust/pyo3-geoarrow/src/offset_buffer.rs: -------------------------------------------------------------------------------- 1 | use arrow_array::cast::AsArray; 2 | use arrow_array::types::Int32Type; 3 | use arrow_buffer::OffsetBuffer; 4 | use arrow_cast::cast; 5 | use arrow_schema::DataType; 6 | use pyo3::exceptions::PyValueError; 7 | use pyo3::prelude::*; 8 | use pyo3_arrow::PyArray; 9 | 10 | use crate::PyGeoArrowError; 11 | 12 | pub struct PyOffsetBuffer(OffsetBuffer); 13 | 14 | impl PyOffsetBuffer { 15 | pub fn into_inner(self) -> OffsetBuffer { 16 | self.0 17 | } 18 | } 19 | 20 | impl<'py> FromPyObject<'py> for PyOffsetBuffer { 21 | fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult { 22 | let ob = ob.extract::()?; 23 | if ob.array().null_count() != 0 { 24 | return Err(PyValueError::new_err(format!( 25 | "Cannot construct offset buffer with nulls. Got {} nulls.", 26 | ob.array().null_count() 27 | ))); 28 | } 29 | let offsets = cast(ob.as_ref(), &DataType::Int32).map_err(PyGeoArrowError::from)?; 30 | let offsets = offsets.as_ref().as_primitive::(); 31 | Ok(Self(OffsetBuffer::new(offsets.values().clone()))) 32 | } 33 | } 34 | --------------------------------------------------------------------------------