Skip to content
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
90 changes: 84 additions & 6 deletions python/sedona/spark/geopandas/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,8 +730,35 @@ def envelope(self):
# def set_precision(self, grid_size, mode="valid_output"):
# raise NotImplementedError("This method is not implemented yet.")

# def representative_point(self):
# raise NotImplementedError("This method is not implemented yet.")
def representative_point(self):
"""Return a point that is guaranteed to be within each geometry.

Returns a ``GeoSeries`` of (cheaply computed) points that are guaranteed
to be within each geometry.

Returns
-------
GeoSeries

Examples
--------
>>> from sedona.spark.geopandas import GeoSeries
>>> from shapely.geometry import Polygon, LineString, Point
>>> s = GeoSeries(
... [
... Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
... LineString([(0, 0), (1, 1), (1, 0)]),
... Point(0, 0),
... ]
... )
>>> s.representative_point()
0 POINT (0.5 0.5)
1 POINT (1 0.5)
2 POINT (0 0)
dtype: geometry

"""
return _delegate_to_geometry_column("representative_point", self)

def minimum_bounding_circle(self):
"""Return a ``GeoSeries`` of geometries representing the minimum bounding
Expand Down Expand Up @@ -803,8 +830,35 @@ def minimum_bounding_radius(self):
# def minimum_clearance(self):
# raise NotImplementedError("This method is not implemented yet.")

# def normalize(self):
# raise NotImplementedError("This method is not implemented yet.")
def normalize(self):
"""Return a ``GeoSeries`` of normalized geometries.

Normalization reorganizes the coordinates in a consistent order,
which can be useful for comparison purposes.

Returns
-------
GeoSeries

Examples
--------
>>> from sedona.spark.geopandas import GeoSeries
>>> from shapely.geometry import Polygon, LineString, Point
>>> s = GeoSeries(
... [
... Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
... LineString([(0, 0), (1, 1)]),
... Point(0, 0),
... ]
... )
>>> s.normalize()
0 POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))
1 LINESTRING (0 0, 1 1)
2 POINT (0 0)
dtype: geometry

"""
return _delegate_to_geometry_column("normalize", self)

def make_valid(self, *, method="linework", keep_collapsed=True):
"""Repairs invalid geometries.
Expand Down Expand Up @@ -869,8 +923,32 @@ def make_valid(self, *, method="linework", keep_collapsed=True):
"make_valid", self, method=method, keep_collapsed=keep_collapsed
)

# def reverse(self):
# raise NotImplementedError("This method is not implemented yet.")
def reverse(self):
"""Return a ``GeoSeries`` with the coordinate order reversed.

Returns
-------
GeoSeries

Examples
--------
>>> from sedona.spark.geopandas import GeoSeries
>>> from shapely.geometry import LineString, Point
>>> s = GeoSeries(
... [
... LineString([(0, 0), (1, 1), (2, 2)]),
... LineString([(0, 0), (1, 0), (1, 1)]),
... Point(0, 0),
... ]
... )
>>> s.reverse()
0 LINESTRING (2 2, 1 1, 0 0)
1 LINESTRING (1 1, 1 0, 0 0)
2 POINT (0 0)
dtype: geometry

"""
return _delegate_to_geometry_column("reverse", self)

def segmentize(self, max_segment_length):
"""Returns a ``GeoSeries`` with vertices added to line segments based on
Expand Down
21 changes: 15 additions & 6 deletions python/sedona/spark/geopandas/geoseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -1030,8 +1030,11 @@ def set_precision(self, grid_size, mode="valid_output"):
raise NotImplementedError("This method is not implemented yet.")

def representative_point(self):
# Implementation of the abstract method.
raise NotImplementedError("This method is not implemented yet.")
spark_expr = stf.ST_PointOnSurface(self.spark.column)
return self._query_geometry_column(
spark_expr,
returns_geom=True,
)

def minimum_bounding_circle(self) -> "GeoSeries":
spark_expr = stf.ST_MinimumBoundingCircle(self.spark.column)
Expand All @@ -1053,8 +1056,11 @@ def minimum_clearance(self):
raise NotImplementedError("This method is not implemented yet.")

def normalize(self):
# Implementation of the abstract method.
raise NotImplementedError("This method is not implemented yet.")
spark_expr = stf.ST_Normalize(self.spark.column)
return self._query_geometry_column(
spark_expr,
returns_geom=True,
)

def make_valid(self, *, method="linework", keep_collapsed=True) -> "GeoSeries":
if method != "structure":
Expand All @@ -1069,8 +1075,11 @@ def make_valid(self, *, method="linework", keep_collapsed=True) -> "GeoSeries":
)

def reverse(self):
# Implementation of the abstract method.
raise NotImplementedError("This method is not implemented yet.")
spark_expr = stf.ST_Reverse(self.spark.column)
return self._query_geometry_column(
spark_expr,
returns_geom=True,
)

def segmentize(self, max_segment_length):
other_series, extended = self._make_series_of_val(max_segment_length)
Expand Down
62 changes: 59 additions & 3 deletions python/tests/geopandas/test_geoseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,21 @@ def test_set_precision(self):
pass

def test_representative_point(self):
pass
geoms = [
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (1, 1), (1, 0)]),
Point(0, 0),
None,
]
s = GeoSeries(geoms)
expected = gpd.GeoSeries(geoms).representative_point()

result = s.representative_point()
self.check_sgpd_equals_gpd(result, expected)

# Check that GeoDataFrame works too
df_result = s.to_geoframe().representative_point()
self.check_sgpd_equals_gpd(df_result, expected)

def test_minimum_bounding_circle(self):
s = GeoSeries(
Expand Down Expand Up @@ -1374,7 +1388,28 @@ def test_minimum_clearance(self):
pass

def test_normalize(self):
pass
s = GeoSeries(
[
Polygon([(0, 0), (1, 0), (1, 1), (0, 1)]),
LineString([(0, 0), (1, 1)]),
Point(0, 0),
None,
]
)
result = s.normalize()
expected = gpd.GeoSeries(
[
shapely.normalize(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])),
shapely.normalize(LineString([(0, 0), (1, 1)])),
shapely.normalize(Point(0, 0)),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)

# Check that GeoDataFrame works too
df_result = s.to_geoframe().normalize()
self.check_sgpd_equals_gpd(df_result, expected)

def test_make_valid(self):
s = sgpd.GeoSeries(
Expand Down Expand Up @@ -1431,7 +1466,28 @@ def test_make_valid(self):
self.check_sgpd_equals_gpd(df_result, expected)

def test_reverse(self):
pass
s = GeoSeries(
[
LineString([(0, 0), (1, 1), (2, 2)]),
LineString([(0, 0), (1, 0), (1, 1)]),
Point(0, 0),
None,
]
)
result = s.reverse()
expected = gpd.GeoSeries(
[
LineString([(2, 2), (1, 1), (0, 0)]),
LineString([(1, 1), (1, 0), (0, 0)]),
Point(0, 0),
None,
]
)
self.check_sgpd_equals_gpd(result, expected)

# Check that GeoDataFrame works too
df_result = s.to_geoframe().reverse()
self.check_sgpd_equals_gpd(df_result, expected)

def test_segmentize(self):
s = GeoSeries(
Expand Down
15 changes: 12 additions & 3 deletions python/tests/geopandas/test_match_geopandas_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,10 @@ def test_set_precision(self):
pass

def test_representative_point(self):
pass
for geom in self.geoms:
sgpd_result = GeoSeries(geom).representative_point()
gpd_result = gpd.GeoSeries(geom).representative_point()
self.check_sgpd_equals_gpd(sgpd_result, gpd_result)

def test_minimum_bounding_circle(self):
for geom in self.geoms:
Expand All @@ -788,7 +791,10 @@ def test_minimum_clearance(self):
pass

def test_normalize(self):
pass
for geom in self.geoms:
sgpd_result = GeoSeries(geom).normalize()
gpd_result = gpd.GeoSeries(geom).normalize()
self.check_sgpd_equals_gpd(sgpd_result, gpd_result)

def test_make_valid(self):
import shapely
Expand Down Expand Up @@ -818,7 +824,10 @@ def test_make_valid(self):
GeoSeries([Point(0, 0)]).make_valid(method="linework")

def test_reverse(self):
pass
for geom in self.geoms:
sgpd_result = GeoSeries(geom).reverse()
gpd_result = gpd.GeoSeries(geom).reverse()
self.check_sgpd_equals_gpd(sgpd_result, gpd_result)

@pytest.mark.skipif(
parse_version(gpd.__version__) < parse_version("0.14.0"),
Expand Down
Loading