Table of Contents

Class S102DatasetProcessor

Namespace
EncDotNet.S100.Datasets.Pipelines
Assembly
EncDotNet.S100.Datasets.Pipelines.dll

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

source IAssetSource
relativePath string
catalogueManager PortrayalCatalogueManager
luaEngine ILuaEngine
crsTransformFactory ICrsTransformFactory

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

path string

Path to the S-102 HDF5 dataset file.

catalogueManager PortrayalCatalogueManager

Supplies the S-102 portrayal catalogue.

luaEngine ILuaEngine

Lua engine that executes the portrayal catalogue's rules.

crsTransformFactory ICrsTransformFactory

Creates 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

string

SafetyContourLayerKey

Layer key of the S-102 safety contour sub-layer.

public const string SafetyContourLayerKey = "s102.safetycontour"

Field Value

string

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

IReadOnlyList<DateTime>

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

AxisOrderAssessment

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

DateTime?

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

DatasetMetadata

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

SpecRef

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

SpecVersionAssessment

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

context RenderContext

Optional render context (palette, mariner, time step).

cancellationToken CancellationToken

Cancellation 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 S125DatasetData or S102CoverageData).

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

query CoverageSampleQuery

The 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

latitude double
longitude double
time DateTime?

Returns

FeatureInfo

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

featureRef string

Ignored.

Returns

FeatureInfo

null.

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

widthPixels int

Output bitmap width in pixels.

heightPixels int

Output bitmap height in pixels.

context RenderContext

Optional render context (palette, mariner settings).

background RgbaColor?

Optional background fill; defaults to opaque white.

cancellationToken CancellationToken

Cancellation token.

Returns

Task<SKBitmap>

A newly allocated bitmap owned by the caller.

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

latitude double

Latitude in decimal degrees (WGS-84).

longitude double

Longitude 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

ValidationReport

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).