Exercises all 18 PostGIS-compatible st_* functions against 5 cargo vessels navigating 10 world ports with 40 GPS position reports, distances, bearings, WKT harbor polygons, and point-in-polygon detection.
-- ============================================================================
-- SETUP, zone, schema, 3 Delta tables
-- ============================================================================
CREATE ZONE IF NOT EXISTS {{zone_name}} TYPE EXTERNAL
COMMENT 'External and Delta tables, demo datasets';
CREATE SCHEMA IF NOT EXISTS {{zone_name}}.maritime
COMMENT 'Maritime shipping, ports, vessels, and GPS positions';
CREATE DELTA TABLE IF NOT EXISTS {{zone_name}}.maritime.ports (
port_id INT, port_name VARCHAR, country VARCHAR,
lat DOUBLE, lng DOUBLE, harbor_wkt VARCHAR
) LOCATION '{{data_path}}/maritime_ports';
CREATE DELTA TABLE IF NOT EXISTS {{zone_name}}.maritime.vessels (
vessel_id INT, vessel_name VARCHAR, vessel_type VARCHAR,
flag_country VARCHAR, deadweight_tons INT
) LOCATION '{{data_path}}/maritime_vessels';
CREATE DELTA TABLE IF NOT EXISTS {{zone_name}}.maritime.positions (
position_id INT, vessel_id INT, lat DOUBLE, lng DOUBLE,
speed_knots DOUBLE, recorded_at VARCHAR
) LOCATION '{{data_path}}/maritime_positions';
-- ============================================================================
-- QUERIES, one per st_* family
-- ============================================================================
-- Great-circle distances between port pairs (km, haversine)
SELECT p1.port_name || ' -> ' || p2.port_name AS route,
ROUND(st_distance(p1.lat, p1.lng, p2.lat, p2.lng) / 1000.0, 0) AS distance_km
FROM {{zone_name}}.maritime.ports p1
CROSS JOIN {{zone_name}}.maritime.ports p2
WHERE (p1.port_id, p2.port_id) IN ((1,3),(2,10),(5,1),(7,9),(8,4),(1,4))
ORDER BY distance_km;
-- Algorithm comparison, haversine vs sphere vs Vincenty (Singapore -> Rotterdam)
SELECT ROUND(st_distance_haversine(p1.lat, p1.lng, p2.lat, p2.lng) / 1000.0, 0) AS haversine_km,
ROUND(st_distance_sphere (p1.lat, p1.lng, p2.lat, p2.lng) / 1000.0, 0) AS sphere_km,
ROUND(st_distance_vincenty(p1.lat, p1.lng, p2.lat, p2.lng) / 1000.0, 0) AS vincenty_km
FROM {{zone_name}}.maritime.ports p1 CROSS JOIN {{zone_name}}.maritime.ports p2
WHERE p1.port_id = 1 AND p2.port_id = 2;
-- Navigation bearings
SELECT p1.port_name || ' -> ' || p2.port_name AS route,
ROUND(st_bearing (p1.lat, p1.lng, p2.lat, p2.lng), 2) AS bearing_deg,
ROUND(st_azimuth (p1.lat, p1.lng, p2.lat, p2.lng), 4) AS azimuth_rad,
ROUND(st_final_bearing(p1.lat, p1.lng, p2.lat, p2.lng), 2) AS final_bearing_deg
FROM {{zone_name}}.maritime.ports p1 CROSS JOIN {{zone_name}}.maritime.ports p2
WHERE (p1.port_id, p2.port_id) IN ((1,3),(2,10),(5,1),(8,4))
ORDER BY p1.port_id;
-- Point-in-polygon, which vessel positions are inside a harbor?
SELECT pos.position_id, pos.vessel_id, v.vessel_name, p.port_name, pos.lat, pos.lng
FROM {{zone_name}}.maritime.positions pos
JOIN {{zone_name}}.maritime.vessels v ON v.vessel_id = pos.vessel_id
CROSS JOIN {{zone_name}}.maritime.ports p
WHERE st_contains(p.harbor_wkt, pos.lat, pos.lng) = true
ORDER BY pos.position_id;
-- Coordinate round-trip
SELECT port_id, port_name,
st_make_point(lng, lat) AS wkt_point,
st_x(st_make_point(lng, lat)) AS extracted_lng,
st_y(st_make_point(lng, lat)) AS extracted_lat
FROM {{zone_name}}.maritime.ports ORDER BY port_id;
-- Harbor areas: Singapore (equator, larger) vs Hamburg (53N, smaller)
SELECT MAX(CASE WHEN port_id = 1 THEN ROUND(st_area(harbor_wkt)/1e6, 2) END) AS area_km2_singapore,
MAX(CASE WHEN port_id = 6 THEN ROUND(st_area(harbor_wkt)/1e6, 2) END) AS area_km2_hamburg
FROM {{zone_name}}.maritime.ports;
-- Nearest port to each vessel's last at-sea position (st_distance + ROW_NUMBER)
WITH last_sea AS (
SELECT pos.vessel_id, pos.lat, pos.lng
FROM {{zone_name}}.maritime.positions pos
WHERE pos.speed_knots > 0
AND pos.position_id = (SELECT MAX(p2.position_id)
FROM {{zone_name}}.maritime.positions p2
WHERE p2.vessel_id = pos.vessel_id AND p2.speed_knots > 0)
),
distances AS (
SELECT v.vessel_name, ls.lat AS vessel_lat, ls.lng AS vessel_lng,
p.port_name,
ROUND(st_distance(ls.lat, ls.lng, p.lat, p.lng) / 1000.0, 0) AS dist_km,
ROW_NUMBER() OVER (PARTITION BY v.vessel_id
ORDER BY st_distance(ls.lat, ls.lng, p.lat, p.lng)) AS rn
FROM {{zone_name}}.maritime.vessels v
JOIN last_sea ls ON ls.vessel_id = v.vessel_id
CROSS JOIN {{zone_name}}.maritime.ports p
)
SELECT vessel_name, vessel_lat, vessel_lng,
port_name AS nearest_port, dist_km AS nearest_dist_km
FROM distances WHERE rn = 1 ORDER BY vessel_name;
-- ============================================================================
-- CLEANUP
-- ============================================================================
DROP DELTA TABLE IF EXISTS {{zone_name}}.maritime.positions WITH FILES;
DROP DELTA TABLE IF EXISTS {{zone_name}}.maritime.vessels WITH FILES;
DROP DELTA TABLE IF EXISTS {{zone_name}}.maritime.ports WITH FILES;
DROP SCHEMA IF EXISTS {{zone_name}}.maritime;
## When to Use Reach for this demo when onboarding to DeltaForge's PostGIS-compatible geometry layer, it is the systematic reference that exercises every st_* function in isolation against independently computed geodesic ground-truth values. Use it to verify that a new storage backend, a new engine build, or a custom function pack returns the expected meters, bearings, and containment results before trusting layered analytics. ## What You Will Learn 1. How to compute intercontinental great-circle distances with `st_distance` (haversine) and compare against `st_distance_sphere` and `st_distance_vincenty` (WGS84 ellipsoid) 2. How to read initial and final compass bearings with `st_bearing`, `st_azimuth` (radians), and `st_final_bearing` 3. How to detect vessels inside a harbor using `st_contains(harbor_wkt, lat, lng)` and its inverse `st_within(lat, lng, harbor_wkt)` 4. How `st_make_point(lng, lat)` round-trips through `st_x` and `st_y` for coordinate construction/extraction 5. How `st_area` on a geodesic polygon shrinks with increasing latitude even when the lat/lng span is fixed (Singapore vs Hamburg at the same 0.02° × 0.02° box) 6. How to combine `st_distance` with a correlated subquery and `ROW_NUMBER()` to find each vessel's nearest port from its last at-sea position ## Prerequisites - DeltaForge GUI running with a workspace open - Write access to an EXTERNAL zone and permission to CREATE SCHEMA - Variables: `{{zone_name}}` (defaults to `external`), `{{data_path}}` for three Delta tables (`ports`, `vessels`, `positions`)