Class AxisOrderCheck
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:
- 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.
- 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.
- A GML
gml:Envelopeis 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. - 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
assessmentAxisOrderAssessmentpositionsIReadOnlyList<GeoPosition>
Returns
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
positionsIEnumerable<GeoPosition>Every position of the dataset, as encoded.
declaredExtentBoundingBoxThe extent the dataset declares, or
null. An implausible extent (latitudes beyond ±90°, or all zero) is ignored.sourcestringWhere the positions come from, quoted in BuildMessage().
normalizesboolWhether the caller swaps the positions when the outcome is Swapped; recorded as Normalized. Pass
falsefrom a reader that only reports.extentIsOrdinalbooltruewhendeclaredExtentwas itself read from ordinals in an assumed order (a GMLgml:Envelope), so it can be swapped just as the positions can;false(the default) when its edges are named (the HDF5westBoundLongitudefamily). 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
nullwhen 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
originLatitudedoubleoriginLongitudedoublespacingLatitudinaldoublespacingLongitudinaldoublenumPointsLatitudinalintnumPointsLongitudinalint
Returns
Swap(GeoPosition)
Returns position with latitude and longitude swapped.
public static GeoPosition Swap(GeoPosition position)
Parameters
positionGeoPosition