Skip to main content

VectorX Function Reference

Overview

VectorX augments the product's native ST_* functions with vector-tile encoding, TIN surface modeling, authority-string CRS handling, antimeridian normalization, distributed-shapely geometry validity, cleaning, and coverage-validity, and legacy-geometry migration.

Key Features

As of v0.5.0 it covers:

  • Vector tile encodinggbx_st_asmvt aggregator + gbx_st_asmvt_pyramid generator for publishing Mapbox Vector Tile (MVT) layers, available in both the lightweight (pyvx) and heavyweight (vectorx) tiers
  • TIN surface modelinggbx_st_triangulate, gbx_st_interpolateelevationbbox, and gbx_st_interpolateelevationgeom for Delaunay triangulation and grid elevation interpolation from Z-valued points, in both tiers (with a constrained/conforming mode selector)
  • CRS stringsgbx_st_crs, gbx_st_setcrs, and gbx_st_transformcrs for reading, stamping, and reprojecting a geometry's coordinate reference system by CRS string (ESRI codes, WKT, PROJ4 — not just an EPSG integer), in both tiers
  • Geometry validitygbx_st_makevalid and gbx_st_explainvalidity for repairing and diagnosing OGC-invalid geometries, lightweight tier only (pyvx)
  • Coverage validitygbx_st_coverageisvalid, gbx_st_coverageinvalidedges (SQL grouped-aggregates), and coverage_simplify (Python-API helper) for validating and simplifying polygon coverages, lightweight tier only (pyvx)
  • Geometry cleaninggbx_st_simplifypreservetopology, gbx_st_removerepeatedpoints, gbx_st_reduceprecision, gbx_st_node, and gbx_st_snap for topology-safe simplification, vertex deduplication, precision reduction, linework noding, and feature snapping, lightweight tier only (pyvx)
  • Antimeridian handlinggbx_st_shiftlongitude, gbx_st_wrapx, and gbx_st_split for normalizing geometries that cross the 180° antimeridian, lightweight tier only (pyvx)
  • OGR-based vector readers — Shapefile, GeoJSON, GeoPackage, FileGDB (heavyweight only)
  • Legacy Mosaic conversiongbx_st_legacyaswkb for migrating geometries written by DBLabs Mosaic, in both tiers
Using these functions
  • Import paths — vector tile encoding: databricks.labs.gbx.pyvx (lightweight) · databricks.labs.gbx.vectorx Python / com.databricks.labs.gbx.vectorx Scala (heavyweight). Legacy Mosaic conversion: databricks.labs.gbx.vectorx.jts.legacy (Python) / com.databricks.labs.gbx.vectorx.jts.legacy (Scala).
  • SQL examples — examples use SQL (and Python where shown); in SQL, VectorX functions are prefixed with gbx_ (e.g. gbx_st_legacyaswkb). For SQL, Python, and Scala usage patterns, see Language Bindings.
  • Geometry input encodings — every gbx_st_* geometry input accepts WKB, EWKB, WKT, and EWKT interchangeably. WKB/WKT carry no SRID; EWKB/EWKT carry one. Pass whichever encoding your upstream produces — no separate conversion step is required.

Tier availability

FunctionLightweight (pyvx)Heavyweight (vectorx)
st_asmvtSupportedSupported
st_asmvt_pyramidSupportedSupported
st_triangulateSupported (constrained)Supported (constrained + conforming)
st_interpolateelevationbboxSupported (constrained)Supported (constrained + conforming)
st_interpolateelevationgeomSupported (constrained)Supported (constrained + conforming)
st_crsSupportedSupported
st_setcrsSupportedSupported
st_transformcrsSupportedSupported
st_legacyaswkbSupportedSupported
st_makevalidSupported
st_explainvaliditySupported
st_coverageisvalidSupported
st_coverageinvalidedgesSupported
coverage_simplifySupported (Python API)
st_simplifypreservetopologySupported
st_removerepeatedpointsSupported
st_reduceprecisionSupported
st_nodeSupported
st_snapSupported
st_shiftlongitudeSupported
st_wrapxSupported
st_splitSupported

Setup

With GeoBrix already installed, register VectorX in your session before running any example. Both tiers alias the module as vx, so every example below is identical regardless of tier — only this import line differs.

from databricks.labs.gbx.pyvx import functions as vx
vx.register(spark)

The examples on this page read from four canonical DataFrames, one per function family. Each is available as a temp view for SQL examples. Point the placeholders at your own data to reproduce the examples:

View / DataFrameSchemaBacked byBacks
tin_surveypts ARRAY<BINARY>, bl ARRAY<BINARY>4 WKB POINT Z forming a 10×10 m square (elevations 0, 0, 10, 5 m)TIN examples: st_triangulate, st_interpolateelevationbbox, st_interpolateelevationgeom
mvt_featuresz INT, x INT, y INT, geom_wkb BINARY, attrs STRUCT<name,id>2 tile-local WKB POINTs in tile (z=0, x=0, y=0)Vector-tile examples: st_asmvt, st_asmvt_pyramid
vector_geomsgeom STRINGEWKT literal 'SRID=4326;POINT (13 42)'CRS examples: st_crs, st_setcrs, st_transformcrs
legacy_geomsgeom_legacy STRUCT<typeId,srid,boundaries,holes>Legacy Mosaic struct for POINT(13, 42)Migration: st_legacyaswkb

All four views are built from inline literals in the doc-test fixture helpers (no external files or /Volumes dependency, so the examples run anywhere): WKB POINT Z mass points for tin_survey, tile-local WKB points for mvt_features, an EWKT string for vector_geoms, and a legacy Mosaic struct for legacy_geoms.


Examples — Conventions

How to read the four tabs

Every function on this page shows one example, expressed identically across four tabs:

TabTierBadge
SQLBoth (default)
Python (light)pyvx lightweight tier
Python (heavy)vectorx heavyweight tierBlue
Scalavectorx heavyweight tierBlue

All four tabs operate on the same input fixture with the same arguments. Where a genuine tier difference exists — a diverging output schema or a mode available only in one tier — the affected tab carries a labeled :::note. A difference without a label is a documentation error.

In each Python example, df = spark.table("<view>") or an equivalent inline spark.sql(...) call loads the canonical fixture. Each SQL example reads FROM <view> or uses an inline CTE — no separate CREATE TEMP VIEW step is shown.

Output representation

The output cells in every function table follow a uniform convention so readers can compare tabs at a glance without decoding byte strings.

Binary geometry ([E]WKB) — geometry returned as BINARY is elided with one token and a format annotation. Use (WKB binary) when the output carries no embedded SRID; (EWKB binary) when an SRID is embedded:

... (WKB binary)
... (EWKB binary)

The WKB bytes are always the canonical output. Decode with ST_GeomFromWKB, ST_GeomFromEWKB, or any ISO WKB reader.

MVT bytesst_asmvt and st_asmvt_pyramid return Mapbox Vector Tile protobufs (BINARY). Output is shown as:

... (MVT binary)

WKT / EWKT strings — short strings are shown in full; longer strings are truncated with a type annotation:

POINT (13 42)
MULTIPOLYGON (((... (WKT)

CRS strings — short authority strings (EPSG:4326, ESRI:54008) are shown in full; long WKT CRS definitions are truncated:

PROJCS["British National Grid", ...] (CRS)

Cell width — output cells are capped at approximately 60 characters. A longer value is truncated with ... and annotated with its type.

Identical-across-tier values — when all four tabs produce the same result (e.g. EPSG:4326 from st_crs), each tab shows that value identically with the same annotation. Genuine tier differences are called out in a labeled :::note.

CRS-family functions return BINARY

gbx_st_setcrs and gbx_st_transformcrs return BINARY (WKB or EWKB) in all input encodings and both tiers — a STRING (WKT/EWKT) input still yields BINARY output. Only gbx_st_crs returns STRING. The clickable pointer to the CRS contract: Coordinate Reference Systems.

Light tab for light-only UDTF generators

gbx_st_asmvt_pyramid, gbx_st_triangulate, gbx_st_interpolateelevationbbox, and gbx_st_interpolateelevationgeom are Python UDTFs in the lightweight tier — they have no Python DataFrame Column form. The Python (light) tab for these functions shows:

spark.sql("SELECT t.* FROM <view>, LATERAL gbx_<fn>(...) t")

This is the same invocation as the SQL tab, driven via Python. SQL LATERAL works for both tiers; the Python DataFrame Column form (.select(vx.fn(...))) is heavyweight-only for these generators.


Vector tile output

Encode features into Mapbox Vector Tile (MVT) protobufs. Pair the per-tile MVT bytes with gbx_pmtiles_agg or the PMTiles writer to publish a vector pyramid as a single .pmtiles archive targeting MapLibre, deck.gl, Mapbox GL JS, or Felt.

Both tiers expose identical st_asmvt / st_asmvt_pyramid names and identical output schemas. st_asmvt is swap-compatible across both the SQL and Python DataFrame APIs. st_asmvt_pyramid is interchangeable at the SQL level (invoked via LATERAL); its Python DataFrame Column form is heavy-only, because the lightweight pyramid is a Python UDTF, which SQL LATERAL calls but the DataFrame API does not expose. The one-line swap:

# Lightweight (pyvx) — Serverless-safe, no JAR
from databricks.labs.gbx.pyvx import functions as vx

# Heavyweight (vectorx) — classic x86 cluster, JAR required
from databricks.labs.gbx.vectorx import functions as vx

# Everything below is identical in both tiers:
vx.register(spark)

Options

st_asmvt takes a layer_name argument (plain string or Column). st_asmvt_pyramid additionally accepts:

ArgumentDefaultDescription
layer_name"layer"MVT layer name embedded in the protobuf.
extent4096MVT tile extent in pixels (MVT v2 standard).

Compute compatibility

AspectLightweight (pyvx)Heavyweight (vectorx)
InstallVolume-staged [light_env6] wheel (install)Init script + JAR
Serverless / shared / ARMSupportedNot supported
Lakeflow declarative pipelinesSupportedNot supported
Execution modelPython UDTF / pandas UDFJVM (Scala + Spark columnar)
JVM accessNone — spark.udf.register onlyRequired

Native attribute typing

Both tiers encode MVT feature attributes with native protobuf value types:

  • Integer / Long → int64 value
  • Float / Double → double value
  • Boolean → bool value
  • String (and anything else) → string value

This means downstream clients (MapLibre GL JS, Mapbox GL JS, deck.gl) receive numbers as numbers and booleans as booleans — enabling numeric data-driven styles, filter expressions, and arithmetic without a client-side parseFloat call.


st_asmvt

LightweightHeavyweight Grouped-agg UDF

Aggregator that encodes a group of features into a single MVT protobuf blob for one (z, x, y) tile. Each groupBy(z, x, y).agg(vx.st_asmvt(...)) call produces the MVT bytes for exactly one tile. Both tiers expose the same grouped-aggregate API and produce identical output bytes — a one-line swap between pyvx and vectorx.

Signature: st_asmvt(geom, attrs, layer_name) → BINARY

Parameters:

  • geom (BINARY) — Feature geometry (WKB, EWKB, WKT, or EWKT) in tile-local coordinates (pixel space, 0..extent). Clip and project each feature to the tile coordinate system upstream before calling this aggregator.
  • attrs (STRUCT<...>) — Per-feature attribute struct. Integer, float, boolean, and string fields are encoded with native MVT protobuf value types.
  • layer_name (STRING or str) — MVT layer name. Pass a plain Python string or a Column.

Returns: BINARY — the MVT protobuf for one tile layer. Feed directly into gbx_pmtiles_agg or the PMTiles Writer.

Composability: The BINARY output is the natural input to gbx_pmtiles_agg for packaging multiple (z, x, y) tiles into a single PMTiles file.

SELECT z, x, y, gbx_st_asmvt(geom_wkb, attrs, 'layer') AS mvt
FROM mvt_features
GROUP BY z, x, y;
Example output
+-+-+-+--------+
|z|x|y|mvt |
+-+-+-+--------+
|0|0|0|[binary]|
+-+-+-+--------+
... (MVT binary)

st_asmvt_pyramid

LightweightHeavyweight Streaming UDTF

Generator that explodes one input feature into one row per intersecting (z, x, y) tile across a zoom range, with MVT bytes already encoded in each row. The per-tile clip and coordinate transform happen inside the function — no upstream ST_Intersection is needed.

Input geometry must be in EPSG:4326 lon/lat. The function handles per-tile projection internally. max_z ≤ 20; total tile count across the zoom range capped at 10⁶.

Signature: gbx_st_asmvt_pyramid(geom, attrs, min_z, max_z, [layer_name], [extent])

Parameters:

  • geom (BINARY) — Feature geometry (WKB, EWKB, WKT, or EWKT) in EPSG:4326 lon/lat.
  • attrs (STRUCT<...>) — Per-feature attributes. Same native-typed encoding as st_asmvt.
  • min_z, max_z (INT) — Inclusive zoom range (0..20).
  • layer_name (STRING, optional) — MVT layer name; defaults to "layer".
  • extent (INT, optional) — MVT tile extent in pixels; defaults to 4096.
SQL invocation form differs between tiers

The lightweight tier is a Python UDTF registered via spark.udtf.register — invoke it with LATERAL (SQL standard table-function syntax):

FROM features, LATERAL gbx_st_asmvt_pyramid(geom_wkb, attrs, 0, 12, 'layer', 4096) t
-- Output columns: t.z, t.x, t.y, t.mvt_bytes (direct)

The heavyweight tier is a JVM generator expression — invoke it with LATERAL VIEW (Hive-style):

FROM features LATERAL VIEW gbx_st_asmvt_pyramid(geom_wkb, attrs, 0, 12, 'layer', 4096) t AS tile
-- Output column: t.tile.z, t.tile.x, t.tile.y, t.tile.mvt_bytes (struct wrapper)

The Python DataFrame Column form (vx.st_asmvt_pyramid(col(...), ...)) is heavyweight-only; the lightweight UDTF has no Column API.

Full pipeline — vector pyramid to PMTiles (lightweight):

from databricks.labs.gbx.pyvx    import functions as vx
from databricks.labs.gbx.pmtiles import functions as px
from pyspark.sql import functions as F

vx.register(spark)
px.register(spark)

# Step 1: explode features → per-tile MVT rows (distributed; LATERAL in SQL)
tiles_df = spark.sql("""
SELECT t.*
FROM features,
LATERAL gbx_st_asmvt_pyramid(geom_wkb, struct(name, id), 0, 10, 'roads', 4096) t
""")

# Step 2: aggregate the per-tile MVT bytes → single PMTiles archive
pmt_bytes = (
tiles_df.agg(
px.pmtiles_agg(
F.col("mvt_bytes"), F.col("z"), F.col("x"), F.col("y"),
'{"name":"roads","attribution":"© My Data"}',
).alias("pmt")
)
.collect()[0]["pmt"]
)

with open("/tmp/roads.pmtiles", "wb") as fh:
fh.write(pmt_bytes)

For larger pyramids that exceed the Spark cell limit, use the PMTiles Writer (pmtiles_gbx for the lightweight tier) instead of pmtiles_agg.

WITH feats AS (
SELECT unhex('010100000000000000000000000000000000000000') AS geom_wkb,
named_struct('name', 'origin', 'id', 1L) AS attrs
)
SELECT t.tile.z AS z, t.tile.x AS x, t.tile.y AS y, t.tile.mvt_bytes AS mvt_bytes
FROM feats
LATERAL VIEW gbx_st_asmvt_pyramid(geom_wkb, attrs, 0, 2, 'layer', 4096) t AS tile;
Example output
+-+-+-+---------+
|z|x|y|mvt_bytes|
+-+-+-+---------+
|0|0|0|[binary] |
|1|1|1|[binary] |
|2|2|2|[binary] |
+-+-+-+---------+
... (MVT binary — one row per intersecting tile across zoom levels 0–2)

Triangulation and elevation

These generators build a Delaunay triangulated irregular network (TIN) from Z-valued mass points and optional breaklines, then either expose the triangles directly or sample the surface on a regular grid to produce elevation points. Useful for surface modeling, DTM/DEM derivation, and elevation sampling from survey point clouds. All three are available in both tiers; breaklines are honored in both.

Triangulation modes: constrained vs conforming

Each TIN function takes a trailing mode argument (default 'constrained'):

ModeTiersBehavior
constrained (default)Lightweight and heavyweightConstrained Delaunay triangulation. Breaklines are honored as forced edges with no Steiner points — the output vertex set is exactly your input mass points plus breakline vertices. Identical algorithm in both tiers, so the result is a seamless cross-tier swap.
conformingHeavyweight onlyJTS conforming-Delaunay triangulation: the mesh may insert additional Steiner points along breakline segments to satisfy the Delaunay property near constraints. Produces a smoother mesh around dense breaklines at the cost of extra vertices.

The lightweight tier raises NotImplementedError on mode='conforming' — it has no Steiner-point refinement. This is a documented, intentional divergence, analogous to the H3 covering note elsewhere in these docs: the two tiers agree exactly in the default (constrained) mode, and the heavyweight tier offers conforming as a deliberate opt-in superset. If you need a result that is byte-identical across tiers, stay on constrained (the default).

Invocation surface

In the lightweight tier these TIN generators are PySpark UDTFs with no Python DataFrame Column form — invoke them via SQL LATERAL (e.g. ... , LATERAL gbx_st_triangulate(...) t), the same pattern as gbx_st_asmvt_pyramid. In the heavyweight tier they are exposed as generator Columns (usable in select(...)) and via SQL LATERAL VIEW. SQL LATERAL works for both tiers; the Python DataFrame Column form is heavyweight-only for these generators.

st_interpolateelevationbbox

LightweightHeavyweight Streaming UDTF

Builds a TIN from mass points and breaklines, then samples elevation on a regular pixel grid covering an explicit bounding box. Use this when you already know the output extent in absolute coordinates — for example, when snapping to a fixed tile extent or aligning with a raster grid.

Signature: gbx_st_interpolateelevationbbox(points_array, breaklines_array, merge_tolerance, snap_tolerance, split_point_finder, xmin, ymin, xmax, ymax, width_px, height_px, srid, [mode])

Parameters:

  • points_array — Mass-point geometries with Z values. Accepts WKB/EWKB/WKT/EWKT.
  • breaklines_array — Breakline geometries (or an empty array).
  • merge_tolerance (DOUBLE) — Merge distance for coincident points.
  • snap_tolerance (DOUBLE) — Snap distance to breakline vertices.
  • split_point_finder (STRING) — Conforming-mesh strategy (e.g. 'NONENCROACHING').
  • xmin, ymin, xmax, ymax (DOUBLE) — Bounding box corners in the coordinate reference system given by srid.
  • width_px, height_px (INT) — Number of grid columns and rows. Together with the bbox dimensions these determine the cell size.
  • srid (INT) — EPSG code of the bounding box coordinates (e.g. 27700 for British National Grid).
  • mode (STRING, optional) — 'constrained' (default, both tiers) or 'conforming' (heavyweight only).

Generator: Emits one row per in-hull grid cell (cells whose centers fall outside the TIN convex hull are dropped). The output schema column is elevation_point (BINARY WKB POINT Z). Use with SQL LATERAL to materialize the grid.

SELECT t.elevation_point
FROM tin_survey
LATERAL VIEW gbx_st_interpolateelevationbbox(pts, bl, 0, 0, 'NONENCROACHING', 0, 0, 10, 10, 3, 3, 0, 'constrained') t AS elevation_point
Example output
+---------------+
|elevation_point|
+---------------+
|[binary] |
|[binary] |
|... |
+---------------+
... (WKB binary — POINT Z geometries, 3×3 elevation grid, 9 rows)

st_interpolateelevationgeom

LightweightHeavyweight Streaming UDTF

Builds a TIN from mass points and breaklines, then samples elevation on a regular grid anchored to a geometry origin with explicit cell sizes. Use this when the grid must be defined relative to a known point — for example, when the grid origin comes from data (a survey control point) or when different rows need different grid placements.

Signature: gbx_st_interpolateelevationgeom(points_array, breaklines_array, merge_tolerance, snap_tolerance, split_point_finder, grid_origin, grid_cols, grid_rows, cell_size_x, cell_size_y, [mode])

Parameters:

  • points_array — Mass-point geometries with Z values. Accepts WKB/EWKB/WKT/EWKT.
  • breaklines_array — Breakline geometries (or an empty array).
  • merge_tolerance (DOUBLE) — Merge distance for coincident points.
  • snap_tolerance (DOUBLE) — Snap distance to breakline vertices.
  • split_point_finder (STRING) — Conforming-mesh strategy (e.g. 'NONENCROACHING').
  • grid_origin — POINT geometry anchoring the top-left corner of the output grid. The output SRID is inherited from this geometry (encode as EWKB/EWKT to carry a non-zero SRID) — no separate srid argument.
  • grid_cols, grid_rows (INT) — Number of grid columns and rows.
  • cell_size_x (DOUBLE) — Horizontal cell size in the geometry's units (positive steps right).
  • cell_size_y (DOUBLE) — Vertical cell size in the geometry's units. Pass a negative value to step downward (standard raster convention, e.g. -10.0 for 10-unit cells stepping south).
  • mode (STRING, optional) — 'constrained' (default, both tiers) or 'conforming' (heavyweight only).

Generator: Emits one row per in-hull grid cell. The output schema column is elevation_point (BINARY WKB POINT Z). Use with SQL LATERAL to materialize the grid.

SELECT t.elevation_point
FROM tin_survey
LATERAL VIEW gbx_st_interpolateelevationgeom(pts, bl, 0, 0, 'NONENCROACHING', unhex('010100000000000000000000000000000000002440'), 3, 3, 3, -3, 'constrained') t AS elevation_point
Example output
+---------------+
|elevation_point|
+---------------+
|[binary] |
|[binary] |
|... |
+---------------+
... (WKB binary — POINT Z geometries, 3×3 origin-anchored grid, 9 rows)

st_triangulate

LightweightHeavyweight Streaming UDTF

Builds a Delaunay TIN from mass-point geometries (with Z values) and optional breakline geometries, emitting one triangle polygon per row. Use this when you need the raw triangulation — e.g., to inspect mesh quality, clip triangles to an area of interest, or feed a custom sampler.

Signature: gbx_st_triangulate(points_array, breaklines_array, merge_tolerance, snap_tolerance, split_point_finder, [mode])

Parameters:

  • points_array — Array column of point geometries with Z values (the mass points that define the surface). Accepts WKB/EWKB/WKT/EWKT.
  • breaklines_array — Array column of linestring geometries that the mesh must honor as edges (e.g., ridge lines, drainage channels). Pass an empty array if no breaklines are needed.
  • merge_tolerance (DOUBLE) — Distance below which coincident points are merged before triangulation.
  • snap_tolerance (DOUBLE) — Distance within which points are snapped to breakline vertices.
  • split_point_finder (STRING) — Conforming-mesh refinement strategy. Use 'NONENCROACHING' for a mesh that avoids encroaching on breakline segments; 'MIDPOINT' is also valid (heavyweight conforming mode).
  • mode (STRING, optional) — 'constrained' (default, both tiers) or 'conforming' (heavyweight only). See Triangulation modes above.

Generator: Emits one row per output triangle. Use with SQL LATERAL to materialize the triangles; the output schema column is triangle (BINARY WKB polygon).

SELECT t.triangle
FROM tin_survey
LATERAL VIEW gbx_st_triangulate(pts, bl, 0, 0, 'NONENCROACHING', 'constrained') t AS triangle
Example output
+--------+
|triangle|
+--------+
|[binary]|
|[binary]|
+--------+
... (WKB binary — 2 Delaunay triangle polygons)
mode='conforming' is heavyweight-only

The 'constrained' mode (default) is available in both tiers. The 'conforming' mode — which inserts Steiner points along breakline segments for a smoother mesh — is heavyweight-only: the lightweight pyvx tier raises NotImplementedError if you pass mode='conforming'. The examples on all tabs use the default 'constrained' mode.


Coordinate reference systems

Read, stamp, and reproject a geometry's CRS by CRS string — an ESRI code, a WKT definition, or a PROJ4 string, not only an EPSG integer. These complement the product's built-in ST_SRID / ST_SetSRID / ST_Transform, which take an integer SRID: use the built-ins when an EPSG code is all you need, and these when the CRS can only be named as a string. See Coordinate Reference Systems for the SRID-vs-CRS-string model shared with RasterX.

All three are available in both tiers under the same names, so a CRS query is a one-line tier swap.

Shared contracts

Geometry input — every geometry argument accepts WKB, EWKB, WKT, and EWKT. WKB/WKT carry no SRID; EWKB/EWKT carry one.

SQL output is always BINARY. gbx_st_setcrs and gbx_st_transformcrs return BINARY (WKB/EWKB) whichever encoding the geometry argument arrived in — a STRING geometry input still yields BINARY. One function has one declared return type: an input-dependent return type cannot be used in a view or any fixed schema, and WKB is how the rest of gbx_st_* and the built-in ST_* functions exchange geometries. To read a CRS back as text, wrap the result in gbx_st_crs; to hand it to a built-in, ST_GeomFromWKB accepts it directly. gbx_st_crs returns STRING.

Errors are the exception, not the rule. These functions degrade rather than fail a whole column:

SituationResult
NULL geometryNULL
NULL target_crsNULL
Geometry has no resolvable source CRS (plain WKB/WKT, no source_crs)input returned unchanged
Embedded SRID is in no registry (e.g. 999999)input returned unchanged
source_crs cannot be parsedinput returned unchanged
target_crs cannot be parsedraises
gbx_st_setcrs given a CRS with no integer authority coderaises

Z coordinates. A geometry whose vertices all carry a finite Z keeps its Z. A genuinely 2D geometry stays 2D — no Z ordinate is invented. For a geometry where only some vertices carry a Z, the current behavior differs between the two operations, because only one of them touches coordinates:

  • gbx_st_transformcrs reprojects it as 2D. Reprojecting a missing Z propagates it into X and Y and destroys the horizontal position, so dropping the Z is what keeps every X/Y correct.
  • gbx_st_setcrs keeps the partial Z as-is, since stamping an SRID never moves coordinates.

A missing Z is never filled in with a substitute value such as 0, which would be indistinguishable from a surveyed elevation downstream. Both tiers behave identically here, in every input encoding.

Known limitations

These apply in every input encoding and on both tiers — they are properties of the operations, not of how you pass the geometry.

  • Chaining setcrstransformcrs on a partial-Z geometry yields a 2D result, for the reason described just above: the reproject drops a partial Z. So a geometry that entered the chain with some elevations leaves it with none.
  • Reprojecting out and back is not bit-exact. A round trip such as EPSG:4326EPSG:32633EPSG:4326 returns 11.000000000000002 where it started at 11 — a floating-point artifact of the projection math, in the last decimal place or two. It does not compound meaningfully: further round trips stay in that same last-place range rather than drifting away. Compare reprojected coordinates with a tolerance, never for exact equality.
  • st_setcrs relabels without reprojecting, so stamping a CRS whose units do not match the coordinates leaves the geometry mislabelled. A later st_transformcrs then transforms from the wrong CRS: projected metres tagged EPSG:4326 come back as Infinity coordinates on the lightweight tier, and raise a projection error on the heavyweight tier. Use st_transformcrs when you want the coordinates moved.
  • Coordinates outside the target CRS's valid domain behave the same way — for example a latitude of 100, which does not exist. The lightweight tier returns Infinity coordinates; the heavyweight tier raises a projection error. Filter to the target CRS's area of use before reprojecting if your input may contain out-of-range coordinates.
  • M (measure) values are dropped. Both tiers carry X, Y and Z only, so a ZM geometry comes back as Z with the measure gone, and a geometry carrying M but no Z comes back plain 2D — no Z is invented to fill the slot. This is worth noting because the product's own geometry type does persist M.

st_crs

LightweightHeavyweight

Returns the canonical CRS string for the geometry's embedded SRID, or NULL.

Signature: gbx_st_crs(geom)

Parameters:

  • geom — Geometry. Accepts WKB/EWKB/WKT/EWKT.

Returns: STRING — the authority string ('EPSG:4326', 'ESRI:54008', …), or NULL for a plain WKB/WKT geometry with no embedded SRID, a NULL input, or an SRID in no known registry.

An SRID is classified against the authoritative PROJ registries, so an ESRI-range code comes back as ESRI:<n> rather than being mislabelled EPSG:<n>.

SELECT gbx_st_crs(geom) AS crs FROM vector_geoms;
Example output
+---------+
|crs |
+---------+
|EPSG:4326|
+---------+

st_setcrs

LightweightHeavyweight

Stamps a CRS on a geometry without reprojecting — it relabels, it does not move coordinates. The counterpart to the built-in ST_SetSRID, taking a CRS string instead of an integer.

Signature: gbx_st_setcrs(geom, crs)

Parameters:

  • geom — Geometry. Accepts WKB/EWKB/WKT/EWKT.
  • crs (STRING) — Target CRS. An authority string ('EPSG:4326', 'ESRI:54008') or an int-castable string / integer (32633, '32633'), which behaves like ST_SetSRID(geom, 32633).

Returns: BINARY — EWKB with the new SRID embedded. Coordinate values are preserved exactly, to the last decimal place — no reprojection and no rounding. (The output bytes are not identical to the input's: embedding the SRID is what makes it EWKB.)

Raises when crs has no integer authority code, because a geometry can store only an integer SRID. That covers:

  • authority-less definitions — a raw PROJCS[...] WKT or a PROJ4 string such as '+proj=utm +zone=33 +datum=WGS84'. PROJ's fuzzy matcher would pair that PROJ4 string with EPSG:32633 at partial confidence, but a geometry SRID is an exact identity claim — a guess is never silently written into one. Use gbx_st_transformcrs if you want the coordinates in that CRS.

    This distinction is not academic: a PROJ4 string that resembles a registry CRS is not necessarily equivalent to it. One that omits a datum shift (+towgs84=0,0,0,0,0,0,0) can place coordinates hundreds of metres from the EPSG code it superficially matches. GeoBrix treats such a definition as its own CRS throughout — including when selecting the transformation used to reproject — rather than silently substituting the near-match. If you want the registry CRS, name it explicitly ('EPSG:28992').

  • non-numeric authority codes'OGC:CRS84', 'IGNF:LAMB93': real, resolvable CRSes whose code simply is not an integer.

SELECT gbx_st_setcrs(geom, 'EPSG:4326') AS stamped FROM vector_geoms;
Example output
+--------+
|stamped |
+--------+
|[binary]|
+--------+
... (EWKB binary — coordinates preserved, SRID=4326 embedded)

st_transformcrs

LightweightHeavyweight

Reprojects a geometry's coordinates into target_crs. The counterpart to the built-in ST_Transform, taking a CRS string instead of an integer — so an ESRI code, a WKT definition, or a PROJ4 string can be a target.

Signature: gbx_st_transformcrs(geom, target_crs [, source_crs])

Parameters:

  • geom — Geometry. Accepts WKB/EWKB/WKT/EWKT.
  • target_crs (STRING) — CRS to reproject into: authority string, int-castable string/integer, WKT, or PROJ4.
  • source_crs (STRING, optional) — CRS the input is in. Used only for a plain (SRID-less) geometry; a geometry that carries an embedded SRID ignores this argument, so a mixed column is safe.

Returns: BINARY — the reprojected geometry.

Which SRID comes out follows the target:

target_crsExampleOutput
Has an integer authority code'EPSG:32633', 'ESRI:54008', 32633EWKB with that SRID stamped — a plain input is upgraded to carry one
Has no integer authority coderaw PROJCS[...] WKT, '+proj=utm +zone=33 …', 'OGC:CRS84'plain WKB: coordinates reprojected, and the now-stale source SRID cleared — leaving it would label the geometry with a CRS it is no longer in

Source CRS resolution order: the geometry's embedded SRID first, then source_crs, and if neither resolves the geometry is returned unchanged.

SELECT gbx_st_transformcrs(geom, 'EPSG:32633') AS utm33n FROM vector_geoms;
Example output
+--------+
|utm33n |
+--------+
|[binary]|
+--------+
... (EWKB binary — POINT(13, 42) reprojected from EPSG:4326 to EPSG:32633)

Geometry validity

Distributed shapely helpers — shapely/GEOS geometry operations running as Python UDFs across your Spark cluster — for diagnosing and repairing OGC-invalid geometries. Lightweight tier only (pyvx); no heavyweight counterpart exists. See Geometry Validity for the full conditional-repair workflow and invalidity reason codes.

st_makevalid

Lightweight

Repairs a geometry to OGC-SFS validity. The default level='linework' nodes self-intersections and applies orient_polygons so output passes the product's stricter ST_IsValid (topology + orientation). level='structure' uses a more conservative overlay method. level='ogc' applies OGC-only repair without orientation normalization.

Signature: gbx_st_makevalid(geom [, level])

Parameters:

  • geom — Geometry to repair. Accepts WKB/EWKB/WKT/EWKT.
  • level (optional) — Repair strategy: 'linework' (default), 'structure', or 'ogc'.

Returns: BINARY — WKB (or EWKB if input carried a SRID). The original CRS is preserved. Returns NULL for null or unparseable input.

See Geometry Validity.

SELECT gbx_st_makevalid('POLYGON((0 0,1 1,1 0,0 1,0 0))') AS clean
Example output
+--------+
|clean |
+--------+
|[binary]|
+--------+
... (WKB binary — repaired geometry; bowtie becomes a valid multi-polygon)

st_explainvalidity

Lightweight

Diagnoses geometry validity and returns a JSON string with four fields: valid (boolean), reason (GEOS reason string), code (stable integer violation class), and location (POINT(x y) WKT string of the violation site). code and location are null when GEOS does not provide them. Use ST_IsValid as a cheap boolean gate and call gbx_st_explainvalidity only on flagged rows.

Signature: gbx_st_explainvalidity(geom)

Parameters:

  • geom — Geometry to diagnose. Accepts WKB/EWKB/WKT/EWKT.

Returns: STRING — JSON {"valid": ..., "reason": ..., "code": ..., "location": ...}. Returns NULL for null or unparseable input.

See Geometry Validity.

SELECT gbx_st_explainvalidity('POLYGON((0 0,1 1,1 0,0 1,0 0))') AS detail
Example output
+--------------------------------------------------------------------+
|detail |
+--------------------------------------------------------------------+
|{"valid": false, "reason": "Self-intersection[0.5 0.5]", "code": 10,|
+--------------------------------------------------------------------+
... (JSON string — {valid, reason, code, location} for SFS validity diagnosis)

Coverage validity

Distributed shapely helpers — grouped-aggregate SQL UDFs and a Python DataFrame helper — for validating and simplifying polygon coverages (sets of polygons that share edges and together partition a region). Lightweight tier only (pyvx); no heavyweight counterpart exists. See Coverage Validity for the gap_width semantics, scale-ceiling notes, and the comparison with per-geometry validity.

st_coverageisvalid

Lightweight grouped-agg

Returns true when the polygon group forms a valid coverage — no overlaps; no gaps thinner than gap_width. Use with GROUP BY to identify which coverage groups pass.

Signature: gbx_st_coverageisvalid(geom, gap_width)

Parameters:

  • geom — Geometry column. Accepts WKB/EWKB/WKT/EWKT. All members must be polygon types.
  • gap_width (DOUBLE, required) — Gap tolerance. Overlaps always invalid; gaps narrower than this are also flagged. Pass 0.0 to detect only overlaps.

Returns: BOOLEAN. NULL when the group is empty.

See Coverage Validity.

SELECT cov_id, gbx_st_coverageisvalid(geom, 0.0) AS is_valid
FROM coverage_parcels
GROUP BY cov_id
Example output
+------+--------+
|cov_id|is_valid|
+------+--------+
|1 |true |
+------+--------+
... (BOOLEAN — true when the polygon group has no overlaps and no slivers narrower than gap_width)

st_coverageinvalidedges

Lightweight grouped-agg

Returns the union of the boundary segments that violate the coverage as BINARY (WKB/EWKB). Empty geometry when the coverage is clean; non-empty when overlaps or slivers exist. Use the output geometry to highlight problem zones on a map.

Signature: gbx_st_coverageinvalidedges(geom, gap_width)

Parameters:

  • geom — Geometry column. Accepts WKB/EWKB/WKT/EWKT. All members must be polygon types.
  • gap_width (DOUBLE, required) — Gap tolerance. Same semantics as gbx_st_coverageisvalid.

Returns: BINARY — WKB/EWKB union of invalid edge segments. Empty geometry when clean. NULL when the group is empty.

See Coverage Validity.

SELECT cov_id, gbx_st_coverageinvalidedges(geom, 0.0) AS bad_edges
FROM coverage_overlap
GROUP BY cov_id
Example output
+------+---------+
|cov_id|bad_edges|
+------+---------+
|1 |[binary] |
+------+---------+
... (BINARY — union of the invalid edge segments; empty geometry when the coverage is clean)

coverage_simplify

Lightweight

Python-API only — no SQL form. Topology-preserving simplification of a whole coverage. Unlike per-row simplification (gbx_st_simplifypreservetopology), this helper simplifies the coverage as a unit so shared edges stay aligned in both adjacent polygons after simplification.

Signature: vx.coverage_simplify(df, group_col, geom_col, tolerance, simplify_boundary=True, out_col="geom_simplified")

Parameters:

  • df — Input Spark DataFrame.
  • group_col — Column name defining coverage groups (e.g. "admin_level").
  • geom_col — Column name of the geometry (WKB/EWKB/WKT/EWKT).
  • tolerance (float) — Simplification tolerance in coordinate units.
  • simplify_boundary (bool, default True) — Whether to simplify the outer boundary.
  • out_col (str, default "geom_simplified") — Output column name.

Returns: A Spark DataFrame — same rows, all original columns, plus out_col (BINARY). N→N.

from databricks.labs.gbx.pyvx import functions as vx
vx.register(spark)

simplified_df = vx.coverage_simplify(
df, group_col="admin_level", geom_col="geom_wkb", tolerance=50.0
)

See Coverage Validity.


Geometry cleaning

Distributed shapely helpers — shapely/GEOS operations running as Python UDFs — for improving the quality of already-valid geometries. If your geometry is invalid, repair it first with gbx_st_makevalid, then clean it. Lightweight tier only (pyvx); no heavyweight counterpart exists. See Geometry Cleaning for usage guidance and the comparison with the product's built-in simplify.

st_simplifypreservetopology

Lightweight

Simplifies a geometry using the Douglas-Peucker algorithm with topology preservation (preserve_topology=True). Vertices that deviate less than tolerance from the simplified line are dropped, but the output geometry is guaranteed to be of the same topological class as the input and to remain valid. Use this instead of the product's st_simplify when ring connectivity must be maintained.

Signature: gbx_st_simplifypreservetopology(geom, tolerance)

Parameters:

  • geom — Geometry to simplify. Accepts WKB/EWKB/WKT/EWKT.
  • tolerance — Simplification tolerance in the geometry's coordinate units.

Returns: BINARY — WKB (or EWKB if input carried a SRID). The original CRS is preserved. Returns NULL for null or unparseable input.

See Geometry Cleaning.

SELECT gbx_st_simplifypreservetopology('POLYGON((0 0,0 5,0.001 8,0 10,10 10,10 0,0 0))', 1.0) AS simplified
Example output
+----------+
|simplified|
+----------+
|[binary] |
+----------+
... (WKB binary — simplified polygon with near-collinear vertex removed, topology preserved)

st_removerepeatedpoints

Lightweight

Removes consecutive duplicate or near-duplicate vertices from a geometry. With the default tolerance=0.0, only exact duplicate consecutive coordinate pairs are removed. A positive tolerance collapses vertices within that distance of their predecessor into a single representative vertex.

Signature: gbx_st_removerepeatedpoints(geom [, tolerance])

Parameters:

  • geom — Geometry to deduplicate. Accepts WKB/EWKB/WKT/EWKT.
  • tolerance (optional, default 0.0) — Distance threshold for consecutive near-duplicate vertices.

Returns: BINARY — WKB (or EWKB if input carried a SRID). The original CRS is preserved. Returns NULL for null or unparseable input.

See Geometry Cleaning.

SELECT gbx_st_removerepeatedpoints('LINESTRING(0 0,0 0,1 1,1 1,2 2)') AS deduped
Example output
+--------+
|deduped |
+--------+
|[binary]|
+--------+
... (WKB binary — linestring with duplicate consecutive vertices removed: LINESTRING(0 0,1 1,2 2))

st_reduceprecision

Lightweight

Snaps coordinates to a precision grid of size grid_size, rounding each coordinate to the nearest multiple of grid_size. Useful for eliminating floating-point noise, aligning data from different sources, or reducing coordinate storage size. Uses GEOS set_precision with mode="valid_output" so the output remains valid even if snapping would otherwise collapse a ring.

Signature: gbx_st_reduceprecision(geom, grid_size)

Parameters:

  • geom — Geometry to snap to grid. Accepts WKB/EWKB/WKT/EWKT.
  • grid_size — Precision grid size in the geometry's coordinate units (e.g. 1.0 for integer coordinates, 0.001 for 3 decimal places).

Returns: BINARY — WKB (or EWKB if input carried a SRID). The original CRS is preserved. Returns NULL for null or unparseable input.

See Geometry Cleaning.

SELECT gbx_st_reduceprecision('POINT(1.234 5.678)', 1.0) AS snapped
Example output
+--------+
|snapped |
+--------+
|[binary]|
+--------+
... (WKB binary — POINT(1.0, 6.0): coordinates snapped to nearest 1.0 grid lines)

st_node

Lightweight

Nodes a geometry's linework by splitting at all self-intersections and pairwise intersections. The result is a MultiLineString (or LineString) where every segment endpoint is a valid node — no two segments cross without sharing an explicit endpoint. Noding is typically a prerequisite for polygonization, planar graph analysis, or building topologically clean networks from raw linework.

Signature: gbx_st_node(geom)

Parameters:

  • geom — Linework geometry to node. Accepts WKB/EWKB/WKT/EWKT. Best suited for LineString and MultiLineString inputs; polygon rings can also be noded.

Returns: BINARY — WKB (or EWKB if input carried a SRID). The original CRS is preserved. Returns NULL for null or unparseable input.

See Geometry Cleaning.

SELECT gbx_st_node('LINESTRING(0 0,10 10,0 10,10 0)') AS noded
Example output
+--------+
|noded |
+--------+
|[binary]|
+--------+
... (WKB binary — MultiLineString: figure-eight split into clean segments at the self-intersection)

st_snap

Lightweight

Snaps geom's vertices onto reference where within tolerance. Any vertex in geom that lies within tolerance distance of a vertex or edge in reference is moved onto that nearest point. Useful for aligning features from different sources that should share boundaries but don't quite meet due to digitizing differences or floating-point noise.

Complements the product's ST_ClosestPoint (exact nearest point, no tolerance gate).

Signature: gbx_st_snap(geom, reference, tolerance)

Parameters:

  • geom — Geometry whose vertices will be snapped. Accepts WKB/EWKB/WKT/EWKT.
  • reference — Reference geometry to snap onto. Accepts WKB/EWKB/WKT/EWKT.
  • tolerance — Maximum snap distance in the geometry's coordinate units.

Returns: BINARY — WKB (or EWKB if input carried a SRID). The SRID of geom is preserved. Returns NULL if either input is null or unparseable.

See Geometry Cleaning.

SELECT gbx_st_snap('LINESTRING(0 0.4,10 0.4)', 'LINESTRING(0 0,10 0)', 0.5) AS snapped
Example output
+--------+
|snapped |
+--------+
|[binary]|
+--------+
... (WKB binary — linestring with near-miss vertices snapped onto the reference at y=0)

Antimeridian handling

These three functions are distributed shapely helpers — shapely/GEOS geometry operations running as Python UDFs across your Spark cluster. They are lightweight tier only (pyvx); no heavyweight counterpart exists. See Antimeridian for the full composition pattern.

st_shiftlongitude

Lightweight

Shifts all longitude (x) coordinates of a geometry from [-180, 180] space into [0, 360] space by adding 360 to any negative x value. Use this as the first step when normalizing a geometry that crosses the 180° antimeridian: after shifting, the crossing polygon becomes contiguous around x=180 and can be cleanly split there.

Signature: gbx_st_shiftlongitude(geom)

Parameters:

  • geom — Geometry. Accepts WKB/EWKB/WKT/EWKT.

Returns: BINARY — WKB with all negative x coordinates shifted by +360.

See Antimeridian.

SELECT gbx_st_shiftlongitude('POLYGON((-170 -10, -150 -10, -150 10, -170 10, -170 -10))') AS shifted
Example output
+--------+
|shifted |
+--------+
|[binary]|
+--------+
... (WKB binary — polygon in [0,360] longitude space, x coordinates shifted to [190,210])

st_wrapx

Lightweight

Wraps x coordinates that exceed a threshold back by a fixed offset. The primary use is the reverse of gbx_st_shiftlongitude: after splitting at x=180, apply gbx_st_wrapx(geom, 180, -360) to the eastern pieces to move them from [180, 360] back into [-180, 0]. Apply only to the pieces where ST_XMax(piece) > 180 — wrapping the western piece's shared 180° edge would produce a malformed geometry.

Signature: gbx_st_wrapx(geom, wrap_x_origin, wrap_direction)

Parameters:

  • geom — Geometry. Accepts WKB/EWKB/WKT/EWKT.
  • wrap_x_origin (DOUBLE) — x threshold above which wrapping is applied (typically 180).
  • wrap_direction (DOUBLE) — offset to add to coordinates that exceed the threshold (typically -360).

Returns: BINARY — WKB with qualifying x coordinates shifted by wrap_direction.

See Antimeridian.

SELECT gbx_st_wrapx('POINT(190 10)', 180, -360) AS wrapped
Example output
+--------+
|wrapped |
+--------+
|[binary]|
+--------+
... (WKB binary — POINT(-170, 10): x=190 wrapped back by -360)

st_split

Lightweight

Splits a geometry by a blade geometry, returning a GEOMETRYCOLLECTION containing all resulting pieces. The primary use is cutting an antimeridian-crossing polygon at the 180° meridian: pass the polygon (already shifted into [0, 360] space by gbx_st_shiftlongitude) and the blade 'LINESTRING(180 -90, 180 90)'.

Signature: gbx_st_split(geom, blade)

Parameters:

  • geom — Geometry to split. Accepts WKB/EWKB/WKT/EWKT.
  • blade — Cutting geometry. Accepts WKB/EWKB/WKT/EWKT.

Returns: BINARY — WKB GEOMETRYCOLLECTION of the resulting pieces.

See Antimeridian.

SELECT gbx_st_split('POLYGON((170 -10, 190 -10, 190 10, 170 10, 170 -10))', 'LINESTRING(180 -90, 180 90)') AS pieces
Example output
+--------+
|pieces |
+--------+
|[binary]|
+--------+
... (WKB binary — GeometryCollection with 2 polygon pieces split at x=180)

Legacy Mosaic conversion

st_legacyaswkb

LightweightHeavyweight

Migrates a legacy DBLabs Mosaic geometry value to standard Well-Known Binary (WKB). Pass the raw legacy geometry column through st_legacyaswkb to obtain a WKB binary that all downstream ST_* functions accept — the practical first step when moving a Mosaic-era table onto the product's native GEOMETRY/GEOGRAPHY types.

A scalar function in both tiers (same registered name, same output bytes), so the migration query is a one-line tier swap.

Parameters: legacyGeometry — Column containing a legacy Mosaic geometry value (e.g. {1, [[[x, y]]], [[]]}).

Returns: BINARY — standard WKB.

Migration notes:

  • Z values are preserved. 3D legacy geometries round-trip through st_legacyaswkb with their Z coordinate intact.
  • Polygon holes (interior rings) are preserved.
  • SRID is applied separately at ingestion. The output is plain WKB and carries no SRID; assign the CRS when you read it back, e.g. ST_GeomFromWKB(gbx_st_legacyaswkb(geom_legacy), 27700).
  • M (measure) values are out of scope for this conversion.
SELECT gbx_st_legacyaswkb(geom_legacy) AS wkb FROM legacy_geoms;
Example output
+--------+
|wkb |
+--------+
|[binary]|
+--------+
... (WKB binary)

Next Steps

  • Quick Start — Register and use VectorX with the legacy example
  • Geometry Validity — diagnose and repair OGC-invalid geometries with gbx_st_explainvalidity and gbx_st_makevalid
  • Coverage Validity — validate and simplify polygon coverages with gbx_st_coverageisvalid, gbx_st_coverageinvalidedges, and coverage_simplify
  • Geometry Cleaning — topology-safe simplification, vertex deduplication, precision reduction, linework noding, and feature snapping
  • Antimeridian — antimeridian composition pattern with full example
  • Choosing an Execution Tier — lightweight vs heavyweight comparison
  • PMTiles Function Reference — Aggregate MVT tiles into a single .pmtiles archive
  • PMTiles Writer — DataSource for streaming large pyramids to a single .pmtiles file
  • Helios notebooks — worked end-to-end example: gbx_st_asmvt + gbx_st_asmvt_pyramid encode San Francisco building footprints into a PMTiles archive (NB01).
  • Benchmarking — light-vs-heavy timing methodology
  • API Overview — All GeoBrix APIs