Table of Contents

Class AxisOrderCheck

Namespace
EncDotNet.S100.DataModel
Assembly
EncDotNet.S100.Core.dll

The shared, dataset-level check for swapped latitude and longitude in producer data (issue #650). Every coverage, station and GML reader runs it once per dataset, after reading the positions as encoded, and applies the outcome to the whole dataset, never per coordinate.

public static class AxisOrderCheck
Inheritance
AxisOrderCheck
Inherited Members

Remarks

The S-100 encodings put latitude first: Part 10b §6.2 for EPSG:4326 in GML, and the named latitude / longitude members and attributes of Part 10c for HDF5. Real producer data swaps them often enough (UKHO S-104 Solent stations, UK S-122, Danish S-128, US NWS / NIC S-411) that readers must check rather than trust.

The check is evidence based and conservative. In order:

  1. Physical bounds. A latitude beyond ±90° can only be a longitude. If any position has one and every longitude is within ±90°, the dataset is Swapped; if the longitudes are out of range too, it is Inconsistent.
  2. Declared extent. When the dataset declares a plausible extent, count the positions inside it as encoded and swapped (padded by 5% of its span, at least 0.01°). At least 75% inside as encoded is AsEncoded; fewer than 25% as encoded and more than 75% swapped is Swapped; anything else is Inconsistent. These are the thresholds the S-122 and S-128 readers used before they shared this check.
  3. A GML gml:Envelope is written in the same ordinal order as the positions, so it can be the swapped one: the IEC S-421 test routes have a longitude-first envelope around latitude-first waypoints, the mirror image of the UK S-122 trial. An envelope that fits only the swapped positions is therefore trusted only when the positions cover at least half its span on both axes, as an envelope computed from the data does; otherwise the outcome is Inconsistent with ExtentMayBeSwapped set. The HDF5 bounding-box attributes name their edges and need no such test.
  4. Otherwise Unverified: latitude first is assumed and the assessment says so.

Only Swapped changes positions; the other outcomes keep them as encoded.

Methods

Apply(AxisOrderAssessment?, IReadOnlyList<GeoPosition>)

Returns positions swapped when assessment is Swapped, and unchanged otherwise.

public static IReadOnlyList<GeoPosition> Apply(AxisOrderAssessment? assessment, IReadOnlyList<GeoPosition> positions)

Parameters

assessment AxisOrderAssessment
positions IReadOnlyList<GeoPosition>

Returns

IReadOnlyList<GeoPosition>

Assess(IEnumerable<GeoPosition>, BoundingBox?, string?, bool, bool)

Assesses the axis order of positions, read as encoded (first ordinate or latitude member as latitude).

public static AxisOrderAssessment? Assess(IEnumerable<GeoPosition> positions, BoundingBox? declaredExtent, string? source = null, bool normalizes = true, bool extentIsOrdinal = false)

Parameters

positions IEnumerable<GeoPosition>

Every position of the dataset, as encoded.

declaredExtent BoundingBox

The extent the dataset declares, or null. An implausible extent (latitudes beyond ±90°, or all zero) is ignored.

source string

Where the positions come from, quoted in BuildMessage().

normalizes bool

Whether the caller swaps the positions when the outcome is Swapped; recorded as Normalized. Pass false from a reader that only reports.

extentIsOrdinal bool

true when declaredExtent was itself read from ordinals in an assumed order (a GML gml:Envelope), so it can be swapped just as the positions can; false (the default) when its edges are named (the HDF5 westBoundLongitude family). An ordinal extent that fits only the swapped positions is trusted only when it fits them tightly; see the remarks on AxisOrderCheck.

Returns

AxisOrderAssessment

The assessment, or null when there are no positions.

GridCorners(double, double, double, double, int, int)

Returns the four corners of a regular grid's footprint, as encoded, for Assess(IEnumerable<GeoPosition>, BoundingBox?, string?, bool, bool): the origin and the far corner along each axis (S-100 Part 10c §10.2.1.2 grid georeferencing).

public static IEnumerable<GeoPosition> GridCorners(double originLatitude, double originLongitude, double spacingLatitudinal, double spacingLongitudinal, int numPointsLatitudinal, int numPointsLongitudinal)

Parameters

originLatitude double
originLongitude double
spacingLatitudinal double
spacingLongitudinal double
numPointsLatitudinal int
numPointsLongitudinal int

Returns

IEnumerable<GeoPosition>

Swap(GeoPosition)

Returns position with latitude and longitude swapped.

public static GeoPosition Swap(GeoPosition position)

Parameters

position GeoPosition

Returns

GeoPosition