This Java file implements a Planetiler profile that converts OpenStreetMap data directly into PMTiles vector tiles for nautical charts. It replaces the previous imposm3 + PostgreSQL workflow.
- Processes all seamark types: buoys, beacons, lights, landmarks, harbours, etc.
- Extracts comprehensive attributes:
osm_id,type,name,reference,function,category,shapecolor,color_pattern(with semicolon → underscore conversion)light(abbreviated format),light_color,light_sequencetopmark_color,topmark_shape(sanitized)
- Creates separate layers:
seamark_point- Point featuresseamark_linestring- Line featuresseamark_polygon- Polygon features with additional label points (PointOnSurface)
Maps standard OSM tags to seamark types:
| OSM Tags | Seamark Type | Category | Geometries |
|---|---|---|---|
route=ferry |
ferry_route |
- | linestring |
waterway:sign=anchor |
anchorage |
- | point/line/polygon |
power=cable + location=underwater |
cable_submarine |
power |
linestring |
man_made=pipeline + location=underwater |
pipeline_submarine |
substance | linestring |
man_made=pier |
mooring |
pier |
point/line/polygon |
leisure=marina |
harbour |
marina |
line/polygon |
leisure=swimming_area|nature_reserve |
restricted_area |
leisure value | line/polygon |
man_made=tower|windmill|gasometer |
landmark |
man_made |
point |
man_made=lighthouse |
lighthouse |
- | point (with full light attributes) |
- Downloads and processes global land polygons from osmdata.openstreetmap.de
- Source:
land-polygons-split-4326.zip(~600 MB) - Projection: WGS84 (EPSG:4326)
- Automatic download on first run if not present
- Creates
landlayer with polygon features - Attributes: None (simple land mask geometry)
- Buffer: 4 pixels for smooth rendering at tile boundaries
Generates geometric representations of light sectors for navigational lights:
- Arcs: Colored sector arcs showing the visible range of each light color
- Rays: Lines at sector boundaries marking the transitions between colors
| Type | Arc Radius | Ray Radius |
|---|---|---|
light_major |
0.7 NM (~1296m) | 2.5 NM (~4630m) |
light_minor |
0.4 NM (~741m) | 1.2 NM (~2222m) |
osm_id(integer) - Reference to parent seamarktype(string) - Parent seamark type (e.g.,light_major,light_minor)subtype(string) - Geometry type:arcorraycolor(string) - Light color for arcs (e.g.,red,green,white)range(string) - Nominal range in nautical milessector_start(integer) - Start bearing in degrees (0-360, for arcs only)sector_end(integer) - End bearing in degrees (0-360, for arcs only)
Processes seamark:light:N:* tags where N is the sector number:
seamark:light:N:colour- Light colorseamark:light:N:range- Nominal rangeseamark:light:N:sector_start- Sector start bearingseamark:light:N:sector_end- Sector end bearing
For a lighthouse with red (0-120°) and green (120-240°) sectors:
- 2 arc features (one red, one green)
- 4 ray features (at 0°, 120°, 120°, 240°)
- Extracts
natural=bayfeatures - Creates point geometry:
- Points: direct geometry
- Lines: centroid point
- Polygons: point on surface
- Attributes:
osm_id,type,subtype,name,reference
Implements automatic defaults for standardized seamark types:
- North: black_yellow horizontal, 2 cones up, black topmark
- East: black_yellow_black horizontal, 2 cones base together, black topmark
- South: yellow_black horizontal, 2 cones down, black topmark
- West: yellow_black_yellow horizontal, 2 cones point together, black topmark
- Color: red_black_red horizontal
- Topmark: 2 spheres, black
- Color: red_white vertical
- Topmark: sphere, red
- Color: yellow
- All beacons: shape = buoyant (transformed from pile)
- All buoys: shape = pillar
- Colors with underscore: color_pattern = horizontal
Replicates SQL seamark_light_abbr() function:
- Format:
<character>(<group>).<COLORS>.<period>s<height>m<range>M - Supports single and multi-light configurations
- Extracts max range per color
- Example:
Fl(3).WRG.10s15m12M
javac -cp planetiler.jar Seamap.javajava -Xmx4g -cp planetiler.jar:. Seamarks \
--download \
--area=austria \
--output=seamarks.pmtiles \
--forceOr for a local OSM file:
java -Xmx4g -cp planetiler.jar:. Seamarks \
--osm-path=data/austria.osm.pbf \
--output=seamarks.pmtiles \
--forceAttributes:
osm_id(integer)type(string) - seamark typename(string)reference(string)function(string)category(string)shape(string)color(string)color_pattern(string)light(string) - abbreviated light characteristicslight_color(string)light_sequence(string)topmark_color(string)topmark_shape(string)
Note: Polygon features also generate a corresponding point feature for labeling (using point on surface).
This command takes about 1h on a strong hetzner machine (Ryzen 9 & 128 GB RAM)
java -Xmx20g -XX:+UseParallelGC -XX:ParallelGCThreads=4 -cp "/app/classes:/app/libs/*:/app/resources:." Seamap.java --download --osm-url=https://planet.openstreetmap.org/pbf/planet-latest.osm.pbf --maxzoom=14 --output=/data/seamap.pmtiles --tmp=/data/tmp --nodemap-type=array --storage=mmap --threads=20 --download-threads=10 --http-retries=3 --force
The seamap.html file provides a complete MapLibre GL JS demonstration of the nautical chart visualization.
- Provider: VersaTiles
- Style: Colorful style with desaturated colors (-30% saturation)
- Purpose: Base map with streets, labels, and general cartography
- Source: MapToolkit Data Connector
- Endpoint:
https://dataconnector.maptoolkit.net/seamap/seamap/{z}/{x}/{y}.pbf - Format: Vector tiles (PMTiles served via API)
- Max Zoom: 14
- Layers:
seamark- All nautical features (buoys, beacons, lights, etc.)land- Land polygons for coastlinelight- Light sector geometries (arcs and rays)
- Source: MapToolkit Icons
- Endpoint:
http://icons.maptoolkit.net/seamap - Format: Sprite sheets with S-57 nautical symbols
- Purpose: Icon rendering for buoys, beacons, landmarks, etc.
- Provider: Mapterhorn
- Endpoint:
https://tiles.mapterhorn.com/{z}/{x}/{y}.webp - Encoding: Terrarium (RGB-encoded elevation)
- Max Zoom: 12
- Features:
- Hillshading with 0.2 exaggeration
- Dynamically generated contour lines
- Contour intervals: 200m/1000m (z7), 100m/500m (z8-9), 50m/200m (z10), 20m/100m (z11), 10m/50m (z12)
- Source: MapToolkit Data Connector (EMODnet Bathymetry 2024)
- Endpoint:
https://dataconnector.maptoolkit.net/seamap/emod/{z}/{x}/{y}.png - Encoding: Terrarium (RGB-encoded depth values)
- Max Zoom: 11
- Coverage: European waters
- Features:
- Bathymetric hillshading (0.2 exaggeration)
- Dynamically generated depth contours
- Contour lines at: 0m, 2m, 5m, 10m, 20m, 50m, 100m, 250m, 500m, 1000m, 2000m, 3000m, 4000m, 5000m
- Depth area fills: 0-2m, 2-5m, 5-10m, 10-20m, 20-50m
- Spot soundings (depth labels) with 32-pixel grid spacing
- MapLibre GL JS: Open-source map rendering engine
- maplibre-contour (v0.2.8): Plugin for dynamic contour generation from DEM tiles
- VersaTiles Style: Base map styling library
The demo visualizes:
- Bathymetry: Colored depth zones with contours and soundings
- Land: Coastline with terrain hillshading and elevation contours
- Seamarks: Buoys, beacons, lights with IALA colors and symbols
- Light Sectors: Colored arcs and rays showing navigational light coverage
- Navigation: Traffic separation schemes, fairways, anchorages
- Hazards: Rocks, wrecks with appropriate symbols
- Infrastructure: Cables, pipelines, platforms, landmarks
Download EMODnet bathymetry dataset (NetCDF format with elevation data for European waters)
wget https://erddap.emodnet.eu/erddap/files/bathymetry_dtm_2024/EMODnet_bathymetry_2024.nc
Download OSM land polygons (global coastline shapefile in WGS84)
wget https://osmdata.openstreetmap.de/download/land-polygons-complete-4326.zip
unzip land-polygons-complete-4326.zip
- Extract elevation layer from NetCDF and convert to GeoTIFF
- Assigns WGS84 coordinate system (EPSG:4326)
- Converts from NetCDF format to standard GeoTIFF raster
gdal_translate -a_srs EPSG:4326 NETCDF:"EMODnet_bathymetry_2024.nc":elevation bathymetry_elevation.tif
- Rasterize land polygons to mask land areas
- burn 0: Set land pixels to elevation 0 (sea level)
- init nan: Initialize all pixels as NaN (no data)
- tr: Target resolution ~0.00104° (~115m at equator, matching EMODnet resolution)
- te: Extent covering Europe (-36°W to 43°E, 15°N to 90°N)
- ot Float32: Output as 32-bit floating point for precise elevation values
gdal_rasterize -burn 0 -init nan -a_nodata nan -tr 0.001041666666666 0.001041666666666 -te -36 15 43 89.999999999933507 -ot Float32 -of GTiff -l land_polygons land-polygons-complete-4326/land_polygons.shp land0.tif
- Merge land mask with bathymetry data
- Overlays land0.tif (land=0) onto bathymetry_elevation.tif (ocean depths)
- Preserves NaN values where no data exists in either source
- Result: Combined raster with land at 0m and bathymetry for sea areas
gdalwarp -overwrite -ot Float32 -srcnodata "nan" -dstnodata "nan" -of GTiff land0.tif bathymetry_elevation.tif merged.tif
- Fill small gaps in data using interpolation
- md 5: Maximum distance of 5 pixels to search for valid values
- Interpolates missing data (NaN) using surrounding valid pixels
- Creates seamless bathymetry raster without gaps
gdal_fillnodata.py -md 5 merged.tif filled.tif
- Create raster-dem tiles
This command takes about 10h on a strong Hetzner machine
rio rgbify -v -e terrarium --min-z 3 --max-z 11 -r -2 -j 4 --format webp filled_clipped.vrt emod.mbtiles
pmtiles convert emod.mbtiles emod.pmtiles

