jiayuasu opened a new issue, #3143: URL: https://github.com/apache/sedona/issues/3143
Part of #2230. ## Summary Implement `GeoSeries.scale(xfact=1.0, yfact=1.0, zfact=1.0, origin="center")` and GeoDataFrame active-geometry delegation. The implementation must remain fully distributed: resolve per-geometry origins and construct a Spark column expression for every row. It must not call `to_geopandas()`, `collect()`, `toLocalIterator()`, or a Python row UDF. Use the existing `ST_Affine` Spark SQL function rather than `ST_Scale` or `ST_ScaleGeom`. The latter functions only scale X/Y and cannot reproduce GeoPandas' default per-geometry origin or `zfact` behavior. ## API and transformation GeoPandas scales each dimension around an origin `(x0, y0, z0)`: ```text x' = x0 + xfact * (x - x0) y' = y0 + yfact * (y - y0) z' = z0 + zfact * (z - z0) ``` This is a 3D affine transformation with diagonal factors and offsets: ```text xoff = x0 - x0 * xfact yoff = y0 - y0 * yfact zoff = z0 - z0 * zfact ``` Supported origins: - `"center"`: each geometry's 2D bounding-box center, computed independently per row; - `"centroid"`: each geometry's 2D centroid, computed independently per row; - a local 2D or 3D Shapely `Point`; - a numeric coordinate tuple containing two or three values. The Z origin is `0.0` for `"center"`, `"centroid"`, and 2D explicit origins. A 3D Point or tuple supplies `z0`. Sedona's Python `ST_Affine` wrapper lists the mandatory 2D arguments before its optional 3D arguments. The implementation must explicitly map the diagonal matrix to this wrapper order rather than passing a GeoPandas-style matrix directly. ## Requirements - Accept operation-wide numeric scalar values for `xfact`, `yfact`, and `zfact`; normalize valid values to Python floats. - Reject `None`, strings, array-like values, distributed Series, and other non-scalar factors with clear errors. - Validate origin keywords, Point dimensionality, tuple length, and numeric tuple values before constructing the Spark expression. - Resolve `"center"` and `"centroid"` using Spark/Sedona column expressions on executors. - Use the 3D `ST_Affine` overload so Z geometries honor `zfact`; 2D geometries must remain 2D. - Preserve index, CRS metadata, geometry SRID, nulls, typed empty geometries, geometry types, and existing Z coordinates when `zfact=1.0`. - Guard empty geometries before evaluating computed-origin expressions so an empty geometry does not become null. - Provide GeoDataFrame behavior through the existing `base.py` geometry-column delegation. - Add no driver-side materialization, Python row UDF, JVM change, or new mandatory dependency. ## Tests Add direct and GeoPandas parity coverage for: - default identity factors and custom X/Y/Z factors; - positive, negative, and zero factors; - `"center"` versus `"centroid"` on an asymmetric geometry; - 2D and 3D tuple origins; - 2D and 3D Shapely Point origins; - 2D inputs with a non-default `zfact` remaining 2D; - Z inputs scaled around implicit and explicit Z origins; - the regression `POINT Z (1 2 3)` with factors `(2, 3, 4)` and default origin producing `POINT Z (1 2 12)`; - points, lines, polygons, multi-geometries, and homogeneous geometry collections; - nulls and typed empty geometries with keyword and explicit origins; - invalid factors and origins; - index, CRS, and SRID preservation; - GeoSeries and GeoDataFrame delegation. Document rather than emulate driver-side behavior for mixed 2D/3D geometry collections, M/ZM ordinates, NaN-Z inputs, and non-finite factors where JTS and Shapely may differ. ## Likely files - `python/sedona/spark/geopandas/base.py` - `python/sedona/spark/geopandas/geoseries.py` - `python/tests/geopandas/test_geoseries.py` - `python/tests/geopandas/test_match_geopandas_series.py` No JVM, Scala, or SQL wrapper changes should be necessary. ## Acceptance criteria - Homogeneous 2D and 3D results match GeoPandas for supported factors and origins. - Execution remains a Spark expression over distributed geometry rows. - No driver collection, local iteration, or Python row UDF is introduced. - Focused tests and the relevant Python matrix pass. - The implementation PR references `Part of #2230` and does not close the epic. ## Non-goals - Accepting a different factor or origin per row. - Changing `ST_Scale`, `ST_ScaleGeom`, or `ST_Affine` in Sedona's JVM or SQL layers. - Implementing `skew` or `translate` in the same pull request. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
