EncDotNet.S100.Datasets.S102
Reader and coverage portrayal pipeline for S-102 Bathymetric Surface datasets.
Overview
This library reads S-102 datasets from HDF5 files and provides coverage data (depth and uncertainty grids) for the portrayal pipeline. Key types include:
S102Dataset— root model containing horizontal CRS, vertical datum, and bathymetric coverages.S102DatasetReader— reads an S-102 dataset from anIHdf5File. The horizontal CRS is resolved from the Edition 3.0.0horizontalCRSroot attribute, falling back to the Edition 2.1horizontalDatumValueattribute when the former is absent, so both editions georeference correctly. TheverticalDatumroot attribute (S-102 Ed 3.0.0 §12.3) is surfaced asS102Dataset.VerticalDatum(an S-100 register code) and resolved to a label byS102CoverageSourceviaEncDotNet.S100.DataModel.VerticalDatums.ReadMetadata(file)is the phased-loading "peek" path (issue #460): it returns aDatasetMetadata(declared spec, grid extent, andHorizontalCrsEpsgfor correct UTM reprojection) computed from the grid georeferencing attributes alone, without reading anydepth/uncertaintyvaluesarrays.S102CoverageSource—ICoverageSourceadapter for the coverage pipeline. Its overview pyramid and residual viewport-stride sampling both min-pool depth and max-pool uncertainty. Every source cell belongs to an output block, and residual blocks are balanced across the sampled footprint so their regular-grid georeferencing remains exact. Overview levels stop before either axis would require a partial 2×2 edge pool. Small-scale sampling therefore cannot skip a narrow shoal that falls between stride lattice points. Coverage read spans reports100.coverage.reducer=min.S102PortrayalCatalogue— coverage portrayal catalogue for depth shading.BathymetryCoverage,BathymetryValue— bathymetric data models.BathymetryCoverage.GroupPathcarries the HDF5 instance path (e.g./BathymetryCoverage/BathymetryCoverage.01) and is used by the validation rule pack as the per-coverageRelatedFeatureId.
Portrayal
Portrayal is PC-driven: S102PortrayalCatalogue executes the
bundled BathymetryCoverage.lua rule (S-102 Edition 3.0.0, Annex B)
through an ILuaEngine and resolves the emitted CoverageColor
tokens (DEPDW, DEPMD, DEPMS, DEPVS, DEPIT, NODTA) against
the bundled ColorProfiles/colorProfile.xml. The Day, Dusk, and
Night palettes are all loaded; SwitchPalette selects the active
mood.
The four S-102 context parameters flow in via MarinerSettings:
FourShades— toggle between two-band (DEPVS / DEPDW split atSafetyContour) and four-band (DEPVS / DEPMS / DEPMD / DEPDW split atShallowContour/SafetyContour/DeepContour) shading.SafetyContour,ShallowContour,DeepContour— depth boundaries in metres.
Invariants (ShallowContour ≤ SafetyContour ≤ DeepContour) are
clamped (with a diagnostic) rather than throwing — the viewer
settings panel surface area means transient out-of-order slider
values must not crash the render pipeline.
Cells whose depth equals S102CoverageSource.FillValue (1,000,000f)
are painted with the active palette's NODTA colour via
CoverageColorScheme.NoDataColor by default. Set
S102PortrayalCatalogue.RenderNoDataFill = false to leave NODATA cells
transparent instead — the correct behaviour when S-102 is overlaid on
another layer (e.g. an S-101 ENC in the viewer), so the un-surveyed
remainder of the rectangular coverage extent does not obscure the chart
beneath.
Validation
A bundled rule pack
(EncDotNet.S100.Datasets.S102.Validation.S102DatasetRules.Default)
evaluates a typed S102Dataset against the S-102 Edition 3.0.0
checklist and emits a ValidationReport of findings. The pack is
invoked automatically by S102DatasetProcessor.Validate() and is
also runnable directly:
var report = S102DatasetRules.Default.Run(dataset);
foreach (var finding in report.Findings)
Console.WriteLine($"{finding.RuleId} {finding.Severity}: {finding.Message}");
| Rule id | Severity | Checks |
|---|---|---|
S102-R-1.1 |
Error | Each coverage's Values.Length equals NumPointsLatitudinal × NumPointsLongitudinal. |
S102-R-2.1 |
Error | NODATA fill in Depth/Uncertainty is exactly 1_000_000f; flags NaN / ±Infinity as illegal sentinel substitutes. |
S102-R-3.1 |
Warning | HorizontalCRS, when set, is a recognised EPSG code (4326, 4269, or WGS-84 UTM band). |
S102-R-3.2 |
Warning | IssueDate, when set, parses as an ISO 8601 date or date-time, basic (20260902) or extended (2026-09-02). |
S102-R-3.3 |
Warning | IssueTime, when set, parses as an ISO 8601 time of day, basic (105406+0000) or extended (10:54:06Z). |
S102-R-4.1 |
Error | Each coverage's origin is valid in HorizontalCRS: lat ∈ [-90, 90] / lon ∈ [-180, 180] when geographic; UTM easting/northing bounds (and reprojects to WGS 84) when projected. |
S102-R-4.2 |
Error | Each coverage's far corner is valid in HorizontalCRS the same way; a geographic extent must not wrap the antimeridian. |
S102-R-5.1 |
Warning | Non-NODATA depth values fall within [-50, 12 000] m (one finding per offending coverage). |
S102-PROJ-SCHEMA |
Error | Defensive surrogate: emitted when the underlying HDF5 dataset fails schema-level parsing inside Validate(). |
Installation
dotnet add package EncDotNet.S100.Datasets.S102