Antimeridian
VectorX ships a set of geometry-processing helpers powered by shapely (GEOS under the hood), running as distributed Python UDFs across your Spark cluster. These functions fill gaps in the product's native ST_* surface — operations that are standard in shapely but have no direct built-in counterpart in Databricks Runtime.
The functions on this page are available in the lightweight (pyvx) tier. Register pyvx before using them in SQL or Python:
from databricks.labs.gbx.pyvx import functions as vx
vx.register(spark)
Geometries that cross the 180° antimeridian (the international date line) are a recurring problem in global datasets: a polygon whose vertices span from 170°E to 170°W appears as a 340°-wide shape in standard [-180, 180] longitude space, breaks bounding-box calculations, and confuses most spatial engines that expect well-behaved planar coordinates.
GeoBrix provides three composable functions — gbx_st_shiftlongitude, gbx_st_split, and gbx_st_wrapx — that together normalize such geometries into a clean MULTIPOLYGON with one piece on each side of the antimeridian. These functions assume geographic coordinates in EPSG:4326 (degrees latitude/longitude).
Composition pattern
The full pattern runs four steps:
- Shift the polygon from
[-180, 180]into[0, 360]longitude space withgbx_st_shiftlongitude. This makes a crossing polygon contiguous — its western vertices (e.g. −170°) move to 190°, and the entire shape now sits around the 180° line without any coordinate-wrap artefacts. - Split the contiguous polygon at the 180° meridian with
gbx_st_split. The result is aGEOMETRYCOLLECTIONcontaining two separate pieces. - Dump the collection with the built-in
ST_Dump, which returns the pieces as anARRAY<GEOMETRY>. Index them positionally —geom_split[0]andgeom_split[1]. - Wrap only the eastern piece back into
[-180, 0]withgbx_st_wrapx. The conditionalCASE WHEN ST_XMax(piece) > 180is essential: the eastern piece (all x ≥ 180) needs wrapping; the western piece (all x ≤ 180) is already in standard longitude range and must not be touched. Applyinggbx_st_wrapxuniformly to both pieces would shift the western piece's 180° shared edge to −180°, producing a 350°-wide polygon instead of a clean 10° strip.
The final ST_Union(geom_0, geom_1) / ST_Multi reassembles the two normalized pieces into a MULTIPOLYGON.
WKB ↔ GEOMETRY bridge
GeoBrix functions operate on BINARY (WKB/EWKB). The built-in product functions (ST_Dump, ST_XMax, ST_Union, ST_Multi, ST_AsText) operate on the product's GEOMETRY type. Where the two meet, bridge with:
ST_GeomFromWKB(wkb_column, 4326)— converts GeoBrix BINARY output to a productGEOMETRYvalue. Pass the SRID (4326) so the pieces share a CRS;ST_Unionrequires its inputs to be in the same spatial reference.ST_AsBinary(geometry_column)— converts a productGEOMETRYvalue back to BINARY for GeoBrix input
The pattern below shows both bridges in context.
Example
WITH raw AS (
SELECT 'POLYGON((170 -10, -170 -10, -170 10, 170 10, 170 -10))' AS wkt
),
pieces AS (
SELECT ST_Dump(
ST_GeomFromWKB(
gbx_st_split(gbx_st_shiftlongitude(wkt), 'LINESTRING(180 -90, 180 90)'),
4326
)
) AS geom_split
FROM raw
),
parts AS (
SELECT
CASE WHEN ST_XMax(geom_split[0]) > 180
THEN ST_GeomFromWKB(gbx_st_wrapx(ST_AsBinary(geom_split[0]), 180, -360), 4326)
ELSE geom_split[0]
END AS geom_0,
CASE WHEN ST_XMax(geom_split[1]) > 180
THEN ST_GeomFromWKB(gbx_st_wrapx(ST_AsBinary(geom_split[1]), 180, -360), 4326)
ELSE geom_split[1]
END AS geom_1
FROM pieces
)
SELECT ST_AsText(ST_Multi(ST_Union(geom_0, geom_1))) AS normalized FROM parts;
+-----------------------------------------------------------------------------------------------------+
|normalized |
+-----------------------------------------------------------------------------------------------------+
|MULTIPOLYGON(((180 -10,170 -10,170 10,180 10,180 -10)),((-180 10,-170 10,-170 -10,-180 -10,-180 10)))|
+-----------------------------------------------------------------------------------------------------+