Skip to content
 
 

Repository files navigation

AI disclosure

Parts of this fork (code, docs, and tooling) were developed with assistance from AI coding tools (including Cursor). Changes were reviewed and accepted by a human maintainer. Upstream SMAC-M (Copyright © 2017 Saab AB / LarsSchy) was not AI-authored; attribution and the MIT license still apply as in LICENSE.

SMAC-M - Scripts for Map And Chart Manager

This project converts nautical S-57 data and displays it with MapServer. It includes utilities to convert an ENC cell from S-57 to a GeoPackage and to create mapfiles for a MapServer WMS service. Python scripts build mapfiles from templates and styling information (simplified S-52 via OpenCPN chartsymbols.xml).

This repository is a fork of LarsSchy/SMAC-M, aimed at making the pipeline more portable (installable smacm package), more maintainable, and better suited to dynamic use — fast full conversion for visualising a .000 cell, and RCID-level patch updates for live editor changes.

greenhead-caostal wingaersheekbeach-harbour

The package enables MapServer to display nautical charts in different colour modes and with alternative colour tables. Currently only simplified S-52 symbology is carried out.

Data handling uses GDAL/OGR. Each ENC cell is converted into one GeoPackage; each S-57 object/geometry combination becomes a layer named CL{n}_{OBJ}_{GEOM} (for example CL5_LIGHTS_POINT). Derived layers include light sectors, light signatures, and X-SNDG soundings.

Legacy scripts under chart-installation/ still cover AML, GeoTIFF, and elevation mapfiles. The modern generate-map-config CLI currently supports the chart format only.

Requirement

  • Your own S-57 dataset (base .000 cell; GDAL applies .001+ updates)
  • GDAL/OGR (to read S-57 and write GeoPackage)
  • Up to date GDAL/OGR S-57 metadata (for S57_PROFILE=iw)
  • Python 3.5+ with pipenv
  • ImageMagick — only if use_pregenerated_symbols = false (Wand regenerates symbols)
  • XMLStarlet — only if you need to bootstrap colour-table CSVs from chartsymbols XML
sudo apt install python3 python3-pip python3-venv gdal-bin python3-gdal \
  build-essential libgdal-dev imagemagick xmlstarlet
echo 'PATH="$HOME/.local/bin/:$PATH"' >>~/.bashrc
pip3 install --user pipenv

Clone SMAC-M and install Python virtual environment

This project uses Pipenv for the virtual environment. After cloning, run pipenv install in the repo root to install dependencies and the editable smacm package (smacm = {editable = true, path = "."} in the Pipfile).

GDAL Python bindings must match the system GDAL version, so install them separately:

pipenv run pip install "GDAL<=$(gdal-config --version)"

Then use pipenv shell, or prefix commands with pipenv run. Console scripts:

  • generate-shapefiles — S-57 → GeoPackage (convert / patch)
  • generate-map-config — GeoPackage + chartsymbols → MapServer .map files
  • generate-toml-config — scaffold a TOML config from CLI flags

Thin wrappers under bin/ call the same entry points.

git clone <this-fork-url>
cd ./SMAC-M
pipenv install
pipenv run pip install "GDAL<=$(gdal-config --version)"
pipenv shell

Upstream: https://github.com/LarsSchy/SMAC-M

Up to date GDAL/OGR

Manual ogrinfo / ogr2ogr use still needs system S-57 CSV metadata. The converter sets OGR_S57_OPTIONS and S57_PROFILE=iw itself when it runs; for shell tools you must export them.

In S-57 OGR driver documentation: The S-57 reader depends on having two supporting files, s57objectclasses.csv, and s57attributes.csv available at runtime… in the directory pointed to by S57_CSV, or in the current working directory.

With S57_PROFILE=iw, GDAL looks for s57objectclasses_iw.csv and s57attributes_iw.csv under the GDAL data directory. Example for GDAL 2.2:

$ ogrinfo --version
GDAL 2.2.2, released ...
$ ls /usr/share/gdal/
2.2
$ wget https://raw.githubusercontent.com/OpenCPN/OpenCPN/master/data/s57data/s57objectclasses.csv
$ wget https://raw.githubusercontent.com/OpenCPN/OpenCPN/master/data/s57data/s57attributes.csv
$ cp s57objectclasses.csv /usr/share/gdal/2.2/s57objectclasses_iw.csv
$ cp s57attributes.csv /usr/share/gdal/2.2/s57attributes_iw.csv
export S57_PROFILE=iw
export OGR_S57_OPTIONS=SPLIT_MULTIPOINT=ON,ADD_SOUNDG_DEPTH=ON,RECODE_BY_DSSI=ON

SPLIT_MULTIPOINT / ADD_SOUNDG_DEPTH are required for soundings and other multipoint data. Quick check:

$ ogrinfo --config S57_PROFILE iw -ro ./datatest/US5OH10M/US5OH10M.000 | grep "SLOTOP"
48: SLOTOP

The package also ships copies of these CSVs under src/smacm/data/shp_s57data/ for postprocess (labels, light codes, object lists). That does not replace the system *_iw.csv files for the OGR driver.

Generating the mapfile

Generate a configuration file

Chart work is driven by a TOML file. Paths under [paths] are relative to the config file’s directory.

Scaffold with generate-toml-config, or copy config.sample.toml:

pipenv run generate-toml-config \
    --chart ./datatest/US5OH10M/US5OH10M.000 \
    -rule-default-color IHO \
    --chartsymbols ./src/smacm/resources/chartsymbols/chartsymbols_S57.xml \
    -enhancedchartdata ./data/chart.gpkg \
    --tablename Paper \
    --displaycategory Standard \
    --rule-set-path ./src/smacm/resources/rules/ \
    -o configfile.toml

--chart must be the base .000 file, not an ENC_ROOT directory. -enhancedchartdata becomes paths.data (GeoPackage file or directory).

Important keys (see the sample for comments):

Key Meaning
paths.chart Base ENC .000 file
paths.data Output GeoPackage path, or a directory that will hold {CELL}.gpkg
paths.map Mapfile output directory
paths.chartsymbols OpenCPN chartsymbols.xml (empty = bundled default)
paths.ruleset Colour tables + layer rules (empty = bundled resources/)
paths.tmp Optional temp dir for atomic GPKG writes (same filesystem as data)
[conversion] output_format gpkg (default); shp reserved for legacy
[mapserver] host WMS ows_onlineresource base URL
use_pregenerated_symbols true (default): copy frozen resources/symbols/; false: regenerate via Wand
point_table / area_table Simplified/Paper, Plain/Symbolized
displaycategory e.g. Standard (Displaybase is always added)
topmark_type rigid or floating
excluded_lookups Lookups to skip (default includes M_QUAL)
[maxscale_shift] Per-layer MAXSCALEDENOM multipliers (e.g. LIGHTS = 0.4)
[symbol_size_override] Force symbol SIZE by name prefix

For the rest of these instructions the configuration file is configfile.toml.

Convert S-57 dataset

Full cell import into one GeoPackage at paths.data (derived layers included):

pipenv run generate-shapefiles configfile.toml convert

Incremental updates when the client already knows which features changed (RCIDs on disk match the edited S-57). Useful for editor / live preview loops:

pipenv run generate-shapefiles configfile.toml patch \
  --layer LIGHTS --geometry POINT --changed-rcids 12345,12346

Other patch options:

  • --deleted-rcids — remove features by RCID (paired with --layer / --geometry)
  • --refresh-layer LIGHTS/POINT — rebuild an entire object/geometry layer
  • Repeat --layer / --geometry / RCID lists for multiple layers in one run
  • -q / --quiet — quieter logging

Re-run convert when update files (.001+) change or after a new edition — the service does not auto-detect source changes. Use patch when a client already knows the RCID set.

Generating mapfiles

pipenv run generate-map-config configfile.toml

Optional format argument defaults to chart. Other values (basechart, geotif, elevation, aml) are accepted by the CLI but not yet ported; use the legacy scripts under chart-installation/generate_map_files/scripts/ for those.

MapServer layers use CONNECTIONTYPE OGR, CONNECTION = the GeoPackage path, and DATA = the CL… layer name. A legacy shapefile tree under {data}/{1..6}/ is still understood for older deployments.

Manage scale of navigation level

Default maximum scale visibility is defined in ./src/smacm/resources/rules/layer_rules/layer_msd.csv:

Navigation Level Max Scale
1 30000000
2 10000000
3 5000000
4 1000000
5 500000
6 100000

If you change those defaults, adjust per-layer shifts in the config ([maxscale_shift]). Example: with level-5 default 500000 and LIGHTS = 0.4, LIGHTS become 200000.

[maxscale_shift]
LIGHTS = 0.4

Enhanced data mapfile limitations

Working with enhanced data builds mapfiles from chartsymbols.xml (OpenCPN). That file has a few errors or limitations that are not currently handled.

  • Layers are ordered by Display Priority. Layers with the same display priority are displayed in an undefined order. If a layer has lookups belonging to different display priorities, the entire layer is displayed at that priority.
  • The data files contain a MinScale / MaxScale information and this is not directly used. We currently separate in only 6 levels:
    • 2000000
    • 600000
    • 150000
    • 50000
    • 25000
  • Basic symbology is created from SY, TE, TX, LC, LS, AP and AC instructions. CS instructions are implemented as a series of these basic instructions subject to the following limitations:
    • TOPMAR does not check other features for floating or rigid platforms. All top marks are displayed as rigid by default. You can choose to display all top marks as floating instead by setting topmark_type = "floating" in the configuration file (or by setting the TOPMARK_FLOATING environment variable).
    • SYMINS does not attempt to use the instructions found in the features' SYMINS attribute. All NEWOBJ features will use the generic symbolization
    • LEGLIN does not take into account the DISTANCE_TAGS value selected by the mariner and does not display the course.
    • OWNSHP always symbolizes as the OWNSHP01 symbol.
    • SOUNDG are drawn as special MapServer labels instead of Presentation Library instructions
    • SNDFRM: All layers with a defined VALSOU field are combined into a single layer that is drawn using the SOUNDG rules. It is not currently possible to exclude layers from this special layer.
    • LIGHTS only selects the color of the symbol. Light arcs are written directly to the mapfile.
    • DEPARE only takes into account the DRVAL2 attribute and renders a flat color.
    • DEPCNT does not draw the contour labels.
    • OBSTRN does not take into account the underwater hazard procedure or low accuracy symbols, and assumes a safety depth of 30 metres
    • WRECKS does not take into account the underwater hazard procedure or low accuracy symbols, and assumes a safety depth of 30 metres
  • Symbols in MapServer are anchored to the map in the center vs in the top-left corner for OpenCPN. This brings a disparity in the symbol placement when they are stacked together.
  • Current implementation stack levels as you zoom in so you get level 1 features and labels in level 2 maps.
  • Symbology can be created from vector and bitmaps. We are only supporting bitmap symbology for points and vector symbology for lines and polygons.
  • TOWERSxx symbols are present twice in the chartsymbols.xml. We only use the second one.
  • SOUNDG labels are set with FORCE TRUE. This make to many appear in the map at small scale.
  • Some layers are excluded from the map as they are useful in a WMS context. Right now only M_QUAL is excluded.
  • Some layers are exported as LINE instead of POLYGON
  • Some layers defined in the chartsymbols.xml are pointing to non-existing data columns:
    • BCNSPP layer (lookup #1781) uses BOYSHP == 1 Expression, but this field is not present. We replaced it by BCNDHP == 1.
    • BCNSPP layer (lookup #1784) uses CATLAM == 1 Expression, but this field is not present. We replaced it by CATSPM == 1.
    • LNDELV layer (lookup #2210) uses HEIGHT TX instruction, but this field is not present. The instruction was removed.
    • RADSTA layer (lookup #1222, #2340) uses COMCHA field for label, but this field is not present. We replaced it by OBJNAM.
    • RDOSTA layer (lookup #2350) uses DGPS field for label, but this field is not present. We replaced it by OBJNAM.
    • RESARE layer (lookup #164) uses SY(ESSARE01) and SY(PSSARE01) symbols, but those symbols are not present. They were removed.
    • TOPMAR layer uses OBJNAM field for label, but this field is not present
    • SOUNDG layer is in display-cat Other, it has been transfered to Standard
  • TE and TX instructions ignore the size specified in the chartsymbols xml file

Generating Symbolset

By default (use_pregenerated_symbols = true), frozen symbol maps under src/smacm/resources/symbols/ are copied into the map output directory when mapfiles are built. Set use_pregenerated_symbols = false to regenerate from OpenCPN chartsymbols via Wand/ImageMagick. Manual symbol generation is not required in the usual workflow.

Testing

Follow those steps to get MapServer up and running: https://github.com/mapserver/mapserver/wiki/Install-mapserver-on-ubuntu-18.04-from-official-repository

Then you should be able to test the configuration in the built-in OpenLayers viewer with:

http://localhost/cgi-bin/mapserv?map=/data/Chart_dir/map/SeaChart_DAY_BRIGHT.map&SERVICE=WMS&REQUEST=Getmap&VERSION=1.1.1&LAYERS=SeaChart_DAY_BRIGHT&srs=EPSG:3006&BBOX=133870,5798110,1541520,7459340&FORMAT=application/openlayers&WIDTH=2000&HEIGHT=1100

NOTE: Adjust to EPSG:3857 (or your CRS) and a suitable BBOX for your data. Set [mapserver] host in the TOML to match your MapServer CGI URL.

NOAA ENC service

The commands used to generate a basic NOAA ENC map service live in noaa/README.noaa.md.

General information

IENC (S-57) data is compiled for a variety of navigational purposes. This project mainly supports the first six:

  • 1 - Overview - For route planning and oceanic crossing.
  • 2 - General - For navigating oceans, approaching coasts and route planning.
  • 3 - Coastal - For navigating along the coastline, either inshore or offshore.
  • 4 - Approach - Navigating the approaches to ports or major channels or through intricate or congested waters.
  • 5 - Harbour - Navigating within ports, harbours, bays, rivers and canals, for anchorages.
  • 6 - Berthing - Detailed data to aid berthing.

On each volume within an exchange set there must be a root directory called ENC_ROOT. Data is published as a .000 base file; updates are .001, .002, and so on. GDAL/OGR applies the update chain when reading the base cell.

NL600021.000
NL600021.001
NL600021.002

A valid data set file must be uniquely identified worldwide by its name:

 CCPRRRRR.EEE
 | | |    |
 | | |    |------------ EEE = update number
 | | |
 | | |----------------- RRRRR = waterway code and waterway distance (kilometre) or
 | |                            identification of the equivalent paper chart number
 | |
 | |------------------- P = navigational purpose
 |
 |--------------------- CC = producer code

About

Scripts to convert nautical data and display it with Mapserver. Focused on speed of conversion and allows for updates for futher optimization for real-time changes.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages