Skip to main content

navcore_math/
lib.rs

1//! Pure navigation math.
2//!
3//! The bottom layer of the navigation core: great circle and rhumb line
4//! sailings, cross-track error, the wind triangle, the current triangle,
5//! VMG and laylines, and a boat's own performance polar. Every item here
6//! is a plain function of its arguments -- no clock, no I/O, no state, no
7//! dependencies. That is what lets the layers above replay a recorded log
8//! deterministically.
9//!
10//! # Units and conventions
11//!
12//! There is one convention throughout, and it is worth reading once:
13//!
14//! - **Angles are degrees**, never radians. Radians exist only inside a
15//!   function body.
16//! - **Bearings, headings and courses are degrees true**, `0.0..360.0`,
17//!   clockwise from north. Magnetic variation is deliberately not handled
18//!   here: it is a property of a place and a date, so it belongs to the
19//!   layer that knows where and when the vessel is.
20//! - **Relative angles** (true and apparent wind angle) are signed,
21//!   `-180.0..=180.0`, measured from the bow, **positive to starboard**.
22//! - **Distances are nautical miles**, **speeds are knots**.
23//! - **Cross-track error is positive when the vessel is to starboard of
24//!   the track.**
25//!
26//! Nothing enforces these at the type level. Newtypes were considered
27//! and rejected: they make formulae meant to be read against a textbook
28//! harder to read, without preventing the mistakes this crate actually
29//! risks. Function and field names carry the unit instead --
30//! `distance_nm`, `bearing_deg`, `speed_kn`.
31//!
32//! # Earth model
33//!
34//! A sphere of radius [`EARTH_RADIUS_NM`], not the WGS84 ellipsoid. Over
35//! the distance of a single leg, the difference is well under the error
36//! in the fix that starts the leg. One consequence worth noting: one
37//! degree of latitude comes out as 60.04 NM rather than exactly 60,
38//! because the nautical mile is a fixed 1852 m while a minute of arc on
39//! the mean sphere is 1853.25 m.
40
41#![forbid(unsafe_code)]
42
43pub mod angle;
44pub mod current;
45pub mod great_circle;
46pub mod polar;
47pub mod position;
48pub mod rhumb;
49pub mod sailing;
50pub mod track;
51pub mod wind;
52
53pub use position::Position;
54
55/// The international definition of the nautical mile, exactly 1852 m.
56/// Exported so other crates converting a `distance_nm` result into
57/// metres for the wire (Signal K's resources are metric) use this value
58/// instead of restating the literal.
59pub const METRES_PER_NM: f64 = 1852.0;
60
61/// Mean radius of the earth in nautical miles.
62///
63/// The IUGG mean radius R₁ = 6_371_008.8 m, divided by the nautical mile's
64/// defined 1852 m. See the module docs for why this does not make a degree
65/// of latitude exactly 60 NM.
66pub const EARTH_RADIUS_NM: f64 = 6_371_008.8 / METRES_PER_NM;
67
68/// The international foot, exactly -- a fixed definition, like
69/// [`METRES_PER_NM`]. Distance and speed stay nautical miles and knots
70/// throughout this crate (see "Units and conventions" above); this
71/// constant exists for converting a length or depth to feet when a
72/// display preference requires it.
73pub const METRES_PER_FOOT: f64 = 0.3048;
74
75/// The statute mile, exactly -- `5280` × [`METRES_PER_FOOT`], a fixed
76/// international definition. Distinct from [`METRES_PER_NM`]: used for
77/// an imperial (non-nautical) display preference, as opposed to a
78/// nautical-imperial one.
79pub const METRES_PER_STATUTE_MILE: f64 = 5280.0 * METRES_PER_FOOT;