1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
//! Marine navigation algorithms: compass and deviation, sailings, dead
//! reckoning, position fixing, passage planning and guidance, tides, the sun,
//! and state estimation.
//!
//! ```text
//! magnetic course = compass course + deviation(compass course)
//! true course = magnetic course + variation
//! ```
//!
//! # Type guarantees
//!
//! Angles carry their reference frame: [`CompassCourse`], [`MagneticCourse`],
//! [`TrueCourse`], [`GyroCourse`], [`Variation`], [`Deviation`],
//! [`RelativeBearing`]. Passing a magnetic course where a true one is expected,
//! or a variation where a course is expected, does not compile. [`Distance`]
//! and [`Speed`] are types, so knots cannot be passed as m/s.
//!
//! Each type enforces its range: a [`Direction`] is finite and in `[0°, 360°)`,
//! a [`Latitude`] in `[-90°, 90°]`, so pure corrections return values, not
//! `Result`.
//!
//! No panics on caller data; invalid input returns a [`NavigationError`].
//!
//! # Example
//!
//! ```rust
//! use kinavis::{
//! navigation_solutions::{
//! convert_compass_course_to_true_course, convert_true_course_to_compass_course,
//! },
//! CompassCourse, DeviationTable, InterpolationMethod, TrueCourse, Variation,
//! };
//!
//! // A swing: deviation observed on every tenth of the compass, 000° to 350°.
//! let table = DeviationTable::from_deviations(&[
//! -2.5, -0.5, 1.6, 4.4, -1.7, 0.0, 1.0, 0.3, -0.9, // 000°..080°
//! 0.5, -1.2, 0.8, -0.3, 1.7, -2.1, 0.4, -0.6, 1.2, // 090°..170°
//! -1.3, 0.0, 0.9, -1.1, 1.5, -0.7, -13.2, -15.7, -17.9, // 180°..260°
//! -19.2, -18.1, 1.8, -0.4, 0.7, -0.2, 1.4, -4.4, -2.9, // 270°..350°
//! ])?;
//!
//! let variation = Variation::new(-2.7)?;
//!
//! // What is the ship actually making good, steering 003° by the compass?
//! let solution = convert_compass_course_to_true_course(
//! CompassCourse::new(3.0)?,
//! variation,
//! &table,
//! InterpolationMethod::Cubic,
//! )?;
//! assert_eq!(format!("{}", solution.course), "358.2°T");
//!
//! // And back again: the inverse solves for the compass course the table is
//! // indexed by, so the two directions agree.
//! let back = convert_true_course_to_compass_course(
//! solution.course,
//! variation,
//! &table,
//! InterpolationMethod::Cubic,
//! )?;
//! assert!((back.course.degrees() - 3.0).abs() < 1e-9);
//!
//! // This swing jumps 12.5° between 230° and 240°, steeper than a compass
//! // can be steered by; the result flags it.
//! assert!(solution.advisories.non_invertible_table);
//! # Ok::<(), kinavis::NavigationError>(())
//! ```
//!
//! # Modules
//!
//! Value types come from [`kinavis_kernel`] and are re-exported under this
//! crate's paths; the algorithms are this crate's own. Adapters that must not
//! pull in the algorithms depend on the kernel alone.
//!
//! - [`angle`] — frame-tagged angles.
//! - [`units`] — angles, distances, speeds, rate of turn.
//! - [`position`] — latitude, longitude, notation.
//! - [`time`] — instants with the time scale in the type; leap-second port.
//! - [`observation`] — a value with its time and quality.
//! - [`gnss`] — satellite fix.
//! - [`geodesy`] — ellipsoids, heights with datum, ECEF, chart datums and their
//! transformation to WGS 84.
//! - [`local`] — NED and other local frames; vectors typed by frame and unit.
//! - [`snapshot`] — read model: position, motion, uncertainty, age.
//! - [`state`] — navigation state aggregate.
//! - [`estimation`] — estimator ports.
//! - [`environment`] — environment ports and the resolved sample.
//! - [`conditions`] — constant and timetabled current and wind, fixed leeway.
//! - [`tides`] — rule of twelfths, secondary ports, tidal diamonds as a current
//! model.
//! - [`sun`] — solar azimuth and altitude, sunrise, sunset, twilights.
//! - [`event`] — events of this crate's use cases.
//! - [`deviation`] — deviation tables, periodic interpolation, coefficient
//! fitting.
//! - [`navigation_solutions`] — course and bearing conversions, gyro error,
//! current triangle.
//! - [`sailings`] — rhumb line, great circle, WGS 84 geodesic, cross-track
//! error.
//! - [`dead_reckoning`] — DR and EP, traverses, leeway.
//! - [`fix`] — position lines, fixes, cocked hats, distance off.
//! - [`relative_motion`] — CPA, radar plotting, avoiding manoeuvre.
//! - [`route`] — passage plans: legs, distances, progress along track.
//! - [`turning`] — leg-to-leg turns: radius or rate of turn, advance and
//! transfer, wheel-over point.
//! - [`guidance`] — what to steer now: track, course to steer, XTE, next
//! wheel-over, events.
//! - [`schedule`] — speed per leg, ETD and ETA, time to go, ahead/behind,
//! required speed.
//! - [`clearance`] — squat (Barrass) and under-keel clearance against the
//! vessel's policy.
//! - [`composite`] — composite great-circle sailing below a limiting latitude,
//! as rhumb legs.
//! - [`anchor`] — anchor watch: swinging circle and dragging detection.
//! - [`mob`] — man overboard datum drifted by current and wind.
//! - [`gnss_intake`] — position from a GNSS fix stream: rejection, loss,
//! acquisition, snapshot.
//! - [`estimator`] — extended Kalman filter over the navigation state: pure
//! steps and a thin shell.
//! - [`observations`] — standard observations: position, velocity, heading,
//! speed through water.
//! - [`error`] — the error type.
//!
//! # Models
//!
//! Spherical sailings use a mean Earth radius of 6371.0088 km;
//! [`sailings::geodesic`] uses the WGS 84 ellipsoid. Position lines are rhumb
//! lines and intersect exactly on a Mercator chart; range fixes and relative
//! motion are planar. Each function documents its model.
//!
//! # Memory
//!
//! No allocation. Deviation tables, routes and error excerpts are stored inline
//! with bounds [`MAX_TABLE_NODES`], [`MAX_WAYPOINTS`] and [`EXCERPT_BYTES`];
//! exceeding them returns [`KernelError::CapacityExceeded`]. Batch computations
//! write into caller-owned buffers (`*_into`). The crate runs on bare metal
//! without an allocator, with memory use known at compile time.
//!
//! Aggregates are therefore large: pass [`DeviationTable`] and [`Route`] by
//! reference.
//!
//! # Feature flags
//!
//! - `std` *(default)* — standard library floating-point maths; implies
//! `alloc`.
//! - `alloc` — `Vec`-returning companions of the `*_into` calls.
//! - `libm` — for `no_std` targets: `--no-default-features --features libm`.
//! - `serde` — serialisation of the value types; deserialisation applies
//! construction-time validation (no latitude of 500°, no duplicate headings
//! in a table). Implies `alloc`.
//!
//! No dependencies in the default configuration.
// An allocator is needed only by the `alloc` convenience functions; test
// modules use `vec!` and `format!`, hence `test`. The bare-metal CI build
// enables neither.
extern crate alloc;
// Kernel modules under this crate's paths, inlined so the docs show one crate.
pub use ;
// Crate-private: numeric primitives and fixed-capacity storage. Public in the
// kernel for adapters, not part of this crate's API.
use ;
/// Runs the crate and project README examples as doctests, so documented
/// numbers cannot drift from the code.
;
;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use InlineStr;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;