Skip to main content

Crs

Struct Crs 

Source
pub struct Crs {
Show 13 fields pub uuid: String, pub kind: &'static str, pub x_offset: f64, pub y_offset: f64, pub z_offset: f64, pub areal_rotation: f64, pub vertical_direction: VerticalDirection, pub vertical_quantity: VerticalQuantity, pub horizontal_uom: Option<String>, pub vertical_uom: Option<String>, pub time_uom: Option<String>, pub projected: CrsKind, pub vertical: CrsKind,
}
Expand description

A coordinate reference system, read the same way in every version.

Fields§

§uuid: String

The uuid of the object this was read from.

§kind: &'static str

Its type name, for a caller that wants to label it.

§x_offset: f64

Offset of the local origin along the first projected axis, in horizontal_uom.

§y_offset: f64

Offset along the second projected axis.

§z_offset: f64

Offset of the local origin along the local vertical axis - counted the way vertical_direction counts, in vertical_uom - from the zero of the vertical datum.

RESQML 2.0.1’s ZOffset is exactly that. eml 2.3’s OriginVerticalCoordinate is not: it is written in the base vertical CRS, its direction and its unit, and read_with converts it - see the module doc.

§areal_rotation: f64

Rotation of the local axes, anticlockwise from the first projected axis, in radians - this view’s own convention, which neither release writes.

Both releases state a clockwise angle measured from the projected Y axis: RESQML 2.0.1’s ArealRotation (“A positive value indicates a clockwise rotation from the projected Y axis”, RESQML TRG 2.0.1 §2.1 p. 10) and eml 2.3’s Azimuth from grid north. read_with negates both on the way in.

§vertical_direction: VerticalDirection

Which way the third, local coordinate counts.

eml 2.3’s VerticalAxis.Direction, never the referenced VerticalCrs’s: that one says which way the datum counts, which is a different fact (common TRG 2.3 §12.34 p. 338, §12.35 p. 339).

§vertical_quantity: VerticalQuantity

Whether the third coordinate is a length or a time.

§horizontal_uom: Option<String>

The unit horizontal coordinates are written in, as the file spells it.

None when the CRS does not say. Not an invitation to assume metres - see Crs::to_metres.

§vertical_uom: Option<String>

The unit the third coordinate is written in.

On an eml 2.3 length system, VerticalAxis.Uom - the unit the stored z is in - and never the VerticalCrs’s uom, which is its datum’s.

On a time system this is not the time unit: RESQML 2.0.1’s LocalTime3dCrs carries VerticalUom for the vertical reference - the ZOffset, a length - and states the axis unit separately in TimeUom. Ask Crs::vertical_axis_uom rather than this field.

§time_uom: Option<String>

The unit of the time axis, when the system has one.

RESQML 2.0.1 puts it in TimeUom, beside a VerticalUom that is a length. eml 2.3 has one VerticalAxis.Uom that is the time unit when IsTime is set, so this stays None there and Crs::vertical_axis_uom falls back correctly.

§projected: CrsKind

The projected system the local one sits in.

§vertical: CrsKind

The vertical system.

Implementations§

Source§

impl Crs

Source

pub fn is_component(&self) -> bool

Whether this is one half of a system rather than a whole one.

eml 2.3 promoted the parts of a coordinate system to top-level objects: a package contains LocalEngineering2dCrs and VerticalCrs objects alongside the LocalEngineeringCompoundCrs that joins them. Reading a part succeeds and gives a perfectly valid half - horizontal placement with no vertical, or the reverse - which is exactly the sort of thing that looks like a complete answer.

A caller iterating over every CRS-shaped object in a package wants this; a caller following a representation’s reference never sees one.

Source

pub fn is_identity(&self) -> bool

Whether this CRS moves a point at all.

The common case in practice, and worth short-circuiting: most local CRSs in real files are the identity with a projected system attached.

Source

pub fn to_projected(&self, point: [f64; 3]) -> [f64; 3]

Place a local point in the projected system.

Rotation, then offset, and the vertical flip when the CRS counts downward - so the result is an elevation whichever way the file was written. Units are not touched: the result is in the CRS’s own units, which to_metres normalises.

§The third coordinate

z_offset + z is where the point sits counted along the local axis from the datum’s zero - both terms count the same way, because read_with has put the eml 2.3 origin into the axis’s sense. Flipping a downward count gives the elevation above the vertical datum, the one convention every caller draws in. With Lutetia’s depth compound - axis down, NGF-IGN69 counting up, OriginVerticalCoordinate 35 (CRS.xsd l. 517-520: “in the base vertical CRS”) - the offset along the axis is −35 and a local depth z lands at 35 − z.

This is the local placement only. Going from here to another EPSG system is crate::reproject.

Source

pub fn from_projected(&self, point: [f64; 3]) -> [f64; 3]

The exact inverse of Crs::to_projected: a placed point back into this CRS’s local frame.

What a point must go through before being stored in an object that references this CRS: RESQML geometry is written in the local frame, and every reader - this workspace’s included - applies the placement on the way out. Storing already-placed coordinates applies the offsets, the rotation and the vertical flip a second time at every read - invisible on a CRS whose origin is (0, 0) and axis is Up, which is every corpus package, and wrong on a real one. The round trip from_projected(to_projected(p)) == p is pinned by a test with all three of an offset, a rotation and a Down axis, because that identity is the whole reason this function exists - and again on a compound whose axis and datum count in opposite directions, the case the conversion of OriginVerticalCoordinate in read_with is about.

Source

pub fn to_metres(&self, point: [f64; 3]) -> Result<[f64; 3], Error>

Place a point and convert it to metres.

The step that is easy to forget and impossible to notice: a file whose ProjectedUom is ft is a perfectly ordinary file, and reading it as metres puts the model 3.28 times too far from the origin with every coordinate still looking plausible.

Errors rather than assuming when a unit is outside the table. A CRS that states no unit at all is taken at its word and left alone - that is the schema’s own default, not a guess.

Source

pub fn vertical_axis_uom(&self) -> Option<&str>

The unit the third coordinate is actually written in.

The one that has to be asked, because the two releases put it in different fields and getting it wrong is a factor of a thousand: ALWYN’s seismic model is a 2.0.1 LocalTime3dCrs whose VerticalUom reads m - perfectly correct, it describes the ZOffset - while the axis itself is in TimeUom. Reading vertical_uom on a time system and handing it to a time conversion is how a millisecond becomes a metre.

Source

pub fn is_time(&self) -> bool

Whether the third coordinate is a travel time rather than a length.

§Why a viewer has to ask

A time-domain surface has no depth, and nothing in the file gives it one: the conversion needs a velocity model the package does not carry, and RESQML deliberately puts the time kind - two-way against one-way - outside the CRS (TRG §12.9 leaves it to the acquisition activity). So Crs::to_metres refuses, which is right.

Crs::to_projected does not refuse, and that is the trap. It applies the offsets and the flip like any other axis and hands back a number, so a seismic horizon at 2 713 milliseconds goes into a scene as z = −2 713 and lands among depth objects at −2 713 metres. Nothing errors, and the two are within about ten percent of each other for real velocities - which is exactly the range in which a wrong picture is indistinguishable from a right one.

A caller drawing several objects together therefore has to know which vertical domain each is in, and say so. This is that question.

Source

pub fn is_metric(&self) -> bool

Whether the coordinates are already in metres, or say nothing.

Trait Implementations§

Source§

impl Clone for Crs

Source§

fn clone(&self) -> Crs

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Crs

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl PartialEq for Crs

Source§

fn eq(&self, other: &Crs) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Crs

Auto Trait Implementations§

§

impl Freeze for Crs

§

impl RefUnwindSafe for Crs

§

impl Send for Crs

§

impl Sync for Crs

§

impl Unpin for Crs

§

impl UnsafeUnpin for Crs

§

impl UnwindSafe for Crs

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more