Class S102DatasetProcessor
IDatasetProcessor for IHO S-102 Bathymetric Surface HDF5 datasets. Exposes the depth grid as an ICoveragePortrayalSource portrayed through the S-102 Lua portrayal catalogue, and renders headless images through the Skia coverage core.
public sealed class S102DatasetProcessor : IDatasetProcessor, IDepthAdjustableProcessor, ICoveragePortrayalSource, IHeadlessImageRenderer, ITimeAwareDatasetProcessor, IDisposable, ILoadedDatasetProjection, ICoverageSampler
- Inheritance
-
S102DatasetProcessor
- Implements
- Inherited Members
- Extension Methods
Remarks
NODATA cells are portrayed transparent rather than with the NODTA fill, so the bathymetry can overlay other layers (e.g. an S-101 ENC) without the unsurveyed remainder of the grid hiding the chart beneath.
Normally created through the S102 registration (used by DatasetPipelineFactory) rather than constructed directly.
Constructors
S102DatasetProcessor(IAssetSource, string, PortrayalCatalogueManager, ILuaEngine, ICrsTransformFactory)
Initializes a new S102DatasetProcessor by reading
the dataset file relativePath from
source (e.g. a FileSystemAssetSource or
ZipAssetSource). Used by exchange-set bulk loading where
a dataset's bytes live inside a ZIP archive.
public S102DatasetProcessor(IAssetSource source, string relativePath, PortrayalCatalogueManager catalogueManager, ILuaEngine luaEngine, ICrsTransformFactory crsTransformFactory)
Parameters
sourceIAssetSourcerelativePathstringcatalogueManagerPortrayalCatalogueManagerluaEngineILuaEnginecrsTransformFactoryICrsTransformFactory
S102DatasetProcessor(string, PortrayalCatalogueManager, ILuaEngine, ICrsTransformFactory)
Initializes a new S102DatasetProcessor by reading and
parsing the HDF5 dataset file at path. The file is
read in full and closed before the constructor returns.
public S102DatasetProcessor(string path, PortrayalCatalogueManager catalogueManager, ILuaEngine luaEngine, ICrsTransformFactory crsTransformFactory)
Parameters
pathstringPath to the S-102 HDF5 dataset file.
catalogueManagerPortrayalCatalogueManagerSupplies the S-102 portrayal catalogue.
luaEngineILuaEngineLua engine that executes the portrayal catalogue's rules.
crsTransformFactoryICrsTransformFactoryCreates the WGS84-to-native CRS transforms used when sampling the grid for GetCoverageInfo(double, double, DateTime?).
Exceptions
- S100DatasetSchemaException
The file does not match the S-102 HDF5 schema. The exception carries the file name.
- S100DatasetNotSupportedException
The file uses an S-102 feature this reader does not support. The exception carries the file name.
Fields
CoverageLimitLayerKey
Layer key of the S-102 coverage-limit sub-layer.
public const string CoverageLimitLayerKey = "s102.coveragelimit"
Field Value
SafetyContourLayerKey
Layer key of the S-102 safety contour sub-layer.
public const string SafetyContourLayerKey = "s102.safetycontour"
Field Value
Properties
AvailableTimes
Always empty: an S-102 bathymetric surface has no time steps. The processor is an ITimeAwareDatasetProcessor only to report IssueTime.
public IReadOnlyList<DateTime> AvailableTimes { get; }
Property Value
AxisOrder
The outcome of the dataset-level axis-order check the reader ran on
the dataset's positions (issue #650), or null when the product
has no positions to check or the reader does not run it. A
Swapped outcome
means the reader swapped latitude and longitude for the whole dataset
(when Normalized
is set). Surfaced by hosts (CLI info, the viewer's dataset list)
and, when swapped or inconsistent, as a {product}-PROJ-AXIS
warning in Validate().
public AxisOrderAssessment? AxisOrder { get; }
Property Value
IssueTime
When the producer issued the dataset (UTC), from its issueDate and
issueTime (see S100IssueTime); null
when the dataset does not say. For a forecast this is usually some time
after the model run it carries.
public DateTime? IssueTime { get; }
Property Value
Metadata
The lightweight, product-agnostic DatasetMetadata for this dataset — its declared specification and, where cheaply derivable, its geographic extent, horizontal CRS, display-scale window, and temporal coverage. Overriding processors derive it once from the already-parsed dataset (never a second parse) and cache it, so hosts can frame a viewport, register a layer, draw an out-of-scale indicator, or gate visibility without re-reading the dataset. The default implementation does not override this and instead returns a fresh, minimal value carrying only Spec on each access; processors that can supply an extent (and other facts) override it with the derive-once-and-cache behaviour above. See issue #467 / #460.
public DatasetMetadata Metadata { get; }
Property Value
Remarks
Derived from the coverage source's already-read georeferencing metadata (root attributes + coverage extent) and the dataset's horizontal CRS — no HDF5 payload is re-read (issue #467, WS1).
Spec
The product specification (name + edition) this dataset declares
conformance to. Each per-spec processor returns a fixed name (e.g.
"S-101"); the edition portion is populated from the dataset itself
(HDF5 productSpecification attribute, GML application
namespace, S-101 ProductSpecificationEdition, etc.) when known,
otherwise defaults to SpecVersion default.
public SpecRef Spec { get; }
Property Value
VersionAssessment
How the dataset's declared product specification edition
(Spec) relates to the version of the catalogue used to
process it, or null when no catalogue self-describes its
version (so no assessment can be made). Computed once at construction
— catalogue resolution is a one-shot per processor — and surfaced by
hosts (CLI info/render, viewer layer list) to warn on a
version mismatch per S-100 Edition 5.2.1 Part 2 §6.
public SpecVersionAssessment? VersionAssessment { get; }
Property Value
VerticalDatum
The vertical datum the surface's depths are relative to: the root
verticalDatum as an S-100 vertical datum code (S-102 Ed 3.0.0
§10.2.1), or null when it isn't declared.
public int? VerticalDatum { get; }
Property Value
- int?
Methods
BuildCoveragePortrayalAsync(RenderContext?, CancellationToken)
Builds an immutable, Mapsui-free snapshot of this dataset's coverage portrayal for the supplied render context. Implementations run under a render gate and materialise the styled coverage (including the selected time step) so the result is safe to convert to Mapsui layers off the gate.
public Task<CoveragePortrayalResult> BuildCoveragePortrayalAsync(RenderContext? context = null, CancellationToken cancellationToken = default)
Parameters
contextRenderContextOptional render context (palette, mariner, time step).
cancellationTokenCancellationTokenCancellation token.
Returns
- Task<CoveragePortrayalResult>
The Mapsui-free coverage portrayal result.
CreateLoadedData()
Allocates the LoadedDatasetData variant wrapping this processor's already-parsed model. Never re-reads the source bytes.
public LoadedDatasetData CreateLoadedData()
Returns
- LoadedDatasetData
The catalog payload wrapping the resident model (e.g. an
S125DatasetDataorS102CoverageData).
Dispose()
Releases the render gate that serializes portrayal and headless rendering.
public void Dispose()
FindSites(CoverageSampleQuery)
Finds the places in this dataset that can answer a sample at the query's point: the grid node nearest to it, or every station of a station-series dataset (the nearest across datasets is chosen later).
public CoverageSiteSearch FindSites(CoverageSampleQuery query)
Parameters
queryCoverageSampleQueryThe point to sample, with the transforms that reproject it into the dataset's CRS.
Returns
- CoverageSiteSearch
The sites, or an empty search when the dataset does not cover the point. Implementations may throw ObjectDisposedException when the dataset was closed during the call.
Remarks
Depth and uncertainty at the cell containing the point; no time dimension.
GetCoverageInfo(double, double, DateTime?)
Samples the bathymetric surface at the supplied geographic
position. Returns a synthetic feature carrying depth and
uncertainty pick attributes; the time argument
is ignored because S-102 surfaces are time-invariant.
public FeatureInfo? GetCoverageInfo(double latitude, double longitude, DateTime? time)
Parameters
Returns
Remarks
NoData cells (S-100 Part 10c §11; S-102 sentinel
1_000_000f) yield "—" for the affected attribute
rather than the raw fill value. Out-of-extent clicks return
null.
GetFeatureInfo(string)
Always returns null: an S-102 grid has no discrete features. Use GetCoverageInfo(double, double, DateTime?) to sample depth at a point.
public FeatureInfo? GetFeatureInfo(string featureRef)
Parameters
featureRefstringIgnored.
Returns
RenderHeadlessAsync(int, int, RenderContext?, RgbaColor?, CancellationToken)
Renders the bathymetric surface to a standalone SKBitmap
through the headless, Mapsui-free Skia coverage core
(CoverageHeadlessRenderer → SkiaCoverageRenderer).
The depth-band colour fill is fitted to the requested pixel rectangle,
preserving aspect against background.
public Task<SKBitmap> RenderHeadlessAsync(int widthPixels, int heightPixels, RenderContext? context = null, RgbaColor? background = null, CancellationToken cancellationToken = default)
Parameters
widthPixelsintOutput bitmap width in pixels.
heightPixelsintOutput bitmap height in pixels.
contextRenderContextOptional render context (palette, mariner settings).
backgroundRgbaColor?Optional background fill; defaults to opaque white.
cancellationTokenCancellationTokenCancellation token.
Returns
SampleBaseDepth(double, double)
Samples this S-102 bathymetric surface at a WGS-84 point and returns the
depth (and co-located uncertainty) in metres, or null when the
point falls outside the grid or the depth cell is NoData. Unlike
GetCoverageInfo(double, double, DateTime?) this returns raw quantities (not a display
FeatureInfo) for the viewer's depth-assimilation pipeline
(S-102 §10.2 BathymetryCoverage; S-100 Part 4a vertical datum).
public S102DepthProbe? SampleBaseDepth(double latitude, double longitude)
Parameters
latitudedoubleLatitude in decimal degrees (WGS-84).
longitudedoubleLongitude in decimal degrees (WGS-84).
Returns
- S102DepthProbe?
The bathymetric sample, or
null.
Validate()
Runs the S-102 normative rule pack (Default) against the parsed dataset and returns the cached report.
public ValidationReport? Validate()
Returns
Remarks
Per docs/design/non-gml-validation.md §5.1, this override
defensively wraps the rule-pack call in a try/catch for
S100DatasetSchemaException. The realistic failure
mode is the reader throwing inside the constructor (in which
case the processor never exists and this method is never
reached); the wrapper is therefore forward-compatible only,
surfacing a single S102-PROJ-SCHEMA finding carrying
the exception's GroupPath, AttributeOrDataset,
and SpecReference per design §5.3.
Validation is a pure function of the parsed dataset; the
report is cached after the first call (mirroring the GML
processors' pattern, see S124DatasetProcessor).