Skip to main content

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.

Lightweight tier only

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:

  1. Shift the polygon from [-180, 180] into [0, 360] longitude space with gbx_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.
  2. Split the contiguous polygon at the 180° meridian with gbx_st_split. The result is a GEOMETRYCOLLECTION containing two separate pieces.
  3. Dump the collection with the built-in ST_Dump, which returns the pieces as an ARRAY<GEOMETRY>. Index them positionally — geom_split[0] and geom_split[1].
  4. Wrap only the eastern piece back into [-180, 0] with gbx_st_wrapx. The conditional CASE WHEN ST_XMax(piece) > 180 is 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. Applying gbx_st_wrapx uniformly 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 product GEOMETRY value. Pass the SRID (4326) so the pieces share a CRS; ST_Union requires its inputs to be in the same spatial reference.
  • ST_AsBinary(geometry_column) — converts a product GEOMETRY value 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;
Example output
+-----------------------------------------------------------------------------------------------------+
|normalized |
+-----------------------------------------------------------------------------------------------------+
|MULTIPOLYGON(((180 -10,170 -10,170 10,180 10,180 -10)),((-180 10,-170 10,-170 -10,-180 -10,-180 10)))|
+-----------------------------------------------------------------------------------------------------+