Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and rename: get_dimensions() #87

Merged
merged 9 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ objects without side-effects (except for ``prepare`` and ``destroy_prepared``).

GeographyType
is_geography
get_dimensions
get_dimension
get_type_id
get_x
get_y
Expand Down
2 changes: 0 additions & 2 deletions docs/api_hidden.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
:toctree: _api_generated/

Geography
Geography.dimensions
Geography.nshape
Projection
Projection.lnglat
Projection.pseudo_mercator
Expand Down
37 changes: 10 additions & 27 deletions src/geography.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ std::int8_t get_type_id(PyObjectGeography obj) {
return static_cast<std::int8_t>(obj.as_geog_ptr()->geog_type());
}

int get_dimensions(PyObjectGeography obj) {
int get_dimension(PyObjectGeography obj) {
// note: in case of a collection with features of different dimensions:
// - Geography::dimension() returns -1
// - s2geography::s2_dimension(geog) returns the max value found in collection
Expand Down Expand Up @@ -309,25 +309,6 @@ void init_geography(py::module &m) {

)pbdoc");

pygeography.def_property_readonly("dimensions",
&Geography::dimension,
R"pbdoc(
Returns the inherent dimensionality of a geometry.

The inherent dimension is 0 for points, 1 for linestrings and 2 for
polygons. For geometry collections it returns either the dimension of
all their features (uniform collections) or -1 (collections with
features of different dimensions). Empty collections and None values
return -1.

)pbdoc");

pygeography.def_property_readonly("nshape", &Geography::num_shapes, R"pbdoc(
Returns the number of elements in the collection, or 1 for simple geography
objects.

)pbdoc");

pygeography.def("__repr__", [](const Geography &geog) {
s2geog::WKTWriter writer(6);
return writer.write_feature(geog.geog());
Expand Down Expand Up @@ -381,12 +362,7 @@ void init_geography(py::module &m) {

)pbdoc");

m.def("get_dimensions",
py::vectorize(&get_dimensions),
py::arg("geography"),
py::pos_only(),
R"pbdoc(get_dimensions(geography, /)

m.def("get_dimension", py::vectorize(&get_dimension), py::arg("geography"), R"pbdoc(
Returns the inherent dimensionality of a geography.

Parameters
Expand All @@ -396,7 +372,7 @@ void init_geography(py::module &m) {

Returns
-------
dimensions : int or array
int or array
The inherent dimension is 0 for points, 1 for linestrings and 2 for
polygons. For geometrycollections it is either the max of the containing
elements or -1 for empty collections.
Expand Down Expand Up @@ -441,6 +417,13 @@ void init_geography(py::module &m) {
float or array
Latitude coordinate value(s).

Returns
-------
dimensions : int or array
The inherent dimension is 0 for points, 1 for linestrings and 2 for
polygons. For geometrycollections it is either the max of the containing
elements or -1 for empty collections.

)pbdoc");

// Geography utils
Expand Down
6 changes: 1 addition & 5 deletions src/spherely.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ EARTH_RADIUS_METERS: float = ...

class Geography:
def __init__(self, *args, **kwargs) -> None: ...
@property
def dimensions(self) -> int: ...
@property
def nshape(self) -> int: ...

class GeographyType:
__members__: ClassVar[dict] = ... # read-only
Expand Down Expand Up @@ -167,7 +163,7 @@ class _VFunc_Nin1optprecision_Nout1(

# Geography properties

get_dimensions: _VFunc_Nin1_Nout1[Literal["get_dimensions"], Geography, Any]
get_dimension: _VFunc_Nin1_Nout1[Literal["get_dimension"], Geography, Any]
get_type_id: _VFunc_Nin1_Nout1[Literal["get_type_id"], int, np.int8]

# Geography creation (scalar)
Expand Down
20 changes: 0 additions & 20 deletions tests/test_creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

def test_point() -> None:
point = spherely.create_point(40.2, 5.2)
assert point.dimensions == 0
assert point.nshape == 1
assert repr(point).startswith("POINT (40.2 5.2")


Expand All @@ -27,8 +25,6 @@ def test_point_empty() -> None:
)
def test_multipoint(points) -> None:
multipoint = spherely.create_multipoint(points)
assert multipoint.dimensions == 0
assert multipoint.nshape == 1
assert repr(multipoint).startswith("MULTIPOINT ((5 50)")


Expand Down Expand Up @@ -74,8 +70,6 @@ def test_multipoint_invalid_geography() -> None:
)
def test_linestring(points) -> None:
line = spherely.create_linestring(points)
assert line.dimensions == 1
assert line.nshape == 1
assert repr(line).startswith("LINESTRING (5 50")


Expand Down Expand Up @@ -127,8 +121,6 @@ def test_linestring_invalid_geography() -> None:
)
def test_multilinestring(lines) -> None:
multiline = spherely.create_multilinestring(lines)
assert multiline.dimensions == 1
assert multiline.nshape == 2
assert repr(multiline).startswith("MULTILINESTRING ((5 50")


Expand Down Expand Up @@ -157,8 +149,6 @@ def test_multilinestring_invalid_geography() -> None:
)
def test_polygon(coords) -> None:
poly = spherely.create_polygon(coords)
assert poly.dimensions == 2
assert poly.nshape == 1
assert repr(poly).startswith("POLYGON ((0 0")


Expand Down Expand Up @@ -263,8 +253,6 @@ def test_polygon_oriented(shell) -> None:
)
def test_polygon_holes(shell, holes) -> None:
poly = spherely.create_polygon(shell, holes=holes)
assert poly.dimensions == 2
assert poly.nshape == 1
assert repr(poly).startswith("POLYGON ((0 0")


Expand Down Expand Up @@ -372,8 +360,6 @@ def test_multipolygons() -> None:

multipoly = spherely.create_multipolygon([poly1, poly2])

assert multipoly.dimensions == 2
assert multipoly.nshape == 1
assert repr(multipoly).startswith("MULTIPOLYGON (((0 0")


Expand Down Expand Up @@ -410,19 +396,13 @@ def test_collection() -> None:

coll = spherely.create_collection(objs)

assert coll.dimensions == -1
assert coll.nshape == 3
assert repr(coll).startswith("GEOMETRYCOLLECTION (")

# TODO: more robust test than using the WKT repr
assert repr(coll).count("POINT") == 1
assert repr(coll).count("LINESTRING") == 1
assert repr(coll).count("POLYGON") == 1

# TODO: test objects are copied (if/when we can update them in place)
# (for now only test that original objects are preserved)
assert [o.nshape for o in objs] == [1, 1, 1]

# test nested collection
coll2 = spherely.create_collection(objs + [coll])

Expand Down
48 changes: 24 additions & 24 deletions tests/test_geography.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_not_geography_raise() -> None:
arr = np.array([1, 2.33, spherely.create_point(30, 6)])

with pytest.raises(TypeError, match="not a Geography object"):
spherely.get_dimensions(arr)
spherely.get_dimension(arr)


def test_get_type_id() -> None:
Expand Down Expand Up @@ -77,7 +77,7 @@ def test_get_type_id() -> None:
assert spherely.get_type_id(geog2) == spherely.GeographyType.POINT.value


def test_get_dimensions() -> None:
def test_get_dimension() -> None:
# test n-d array
expected = np.array([[0, 0], [1, 0]], dtype=np.int32)
geog = np.array(
Expand All @@ -89,11 +89,31 @@ def test_get_dimensions() -> None:
],
]
)
actual = spherely.get_dimensions(geog)
actual = spherely.get_dimension(geog)
np.testing.assert_array_equal(actual, expected)

# test scalar
assert spherely.get_dimensions(spherely.create_point(5, 40)) == 0
assert spherely.get_dimension(spherely.create_point(5, 40)) == 0


@pytest.mark.parametrize(
"empty_geog, expected",
[
(spherely.create_point(), 0),
(spherely.create_linestring(), 1),
(spherely.create_polygon(), 2),
(spherely.create_collection([]), -1),
],
)
def test_get_dimension_empty(empty_geog, expected) -> None:
assert spherely.get_dimension(empty_geog) == expected


def test_get_dimension_collection() -> None:
geog = spherely.create_collection(
[spherely.create_point(0, 0), spherely.create_polygon([(0, 0), (1, 1), (2, 0)])]
)
assert spherely.get_dimension(geog) == 2


def test_get_x_y() -> None:
Expand Down Expand Up @@ -127,26 +147,6 @@ def test_get_x_y() -> None:
spherely.get_y(spherely.create_linestring([(0, 1), (1, 2)]))


@pytest.mark.parametrize(
"empty_geog, expected",
[
(spherely.create_point(), 0),
(spherely.create_linestring(), 1),
(spherely.create_polygon(), 2),
(spherely.create_collection([]), -1),
],
)
def test_get_dimensions_empty(empty_geog, expected) -> None:
assert spherely.get_dimensions(empty_geog) == expected


def test_get_dimensions_collection() -> None:
geog = spherely.create_collection(
[spherely.create_point(0, 0), spherely.create_polygon([(0, 0), (1, 1), (2, 0)])]
)
assert spherely.get_dimensions(geog) == 2


def test_prepare() -> None:
# test array
geog = np.array(
Expand Down
Loading