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
//! # π geo3d
//!
//! **3D positions on Earth, made simple.**
//!
//! Give geo3d a GPS position, then ask everyday questions:
//!
//! - π Where is that plane, seen from here?
//! - π‘ Which way should the antenna point?
//! - π How far apart are they?
//! - π Can they see each other?
//! - π₯ Are they going to collide?
//!
//! It's pure Rust, with no dependencies.
//!
//! ```
//! use geo3d::{Geodetic, LocalFrame};
//!
//! let me = Geodetic::new(51.5, -0.12, 30.0); // latitude, longitude, height in metres
//! let plane = Geodetic::new(51.6, -0.12, 3_000.0);
//!
//! let look = LocalFrame::new(me).look_angles(plane); // which way to point
//! // due north, 14.9Β° up, 11.5 km away
//! assert!(look.elevation_deg > 14.0 && look.range_m > 11_000.0);
//! ```
//!
//! # β¨ Why geo3d?
//!
//! - π― **Accurate.** Conversions are exact, and distances along the ground are good to 15
//! nanometres. Everything is tested against GeographicLib, the reference library.
//! - π‘οΈ **Reliable.** It handles the tricky places, like the poles and opposite sides of the Earth,
//! without NaN or panics.
//! - π§© **Easy to use.** Degrees and metres everywhere, with named fields. Latitude always comes first.
//! - πͺΆ **Light and fast.** No dependencies, no `unsafe` code, and nothing allocates. Works on Rust
//! 1.85 and newer.
//!
//! # πΊοΈ The basics
//!
//! Latitude and longitude are angles, so you can't subtract two of them to get a distance. geo3d
//! turns positions into frames where normal 3D maths works.
//!
//! | Type | What it holds | Units |
//! |---|---|---|
//! | [`Geodetic`] | latitude, longitude and height, like GPS gives you | degrees, metres |
//! | [`Ecef`] | x, y, z from the centre of the Earth | metres |
//! | [`Enu`] / [`Ned`] | how far east, north and up (or north, east and down) from you | metres |
//! | [`Aer`] | azimuth, elevation and range: which way to point | degrees, metres |
//! | [`Eci`] | x, y, z that don't spin with the Earth, for satellites | metres |
//! | [`Vec3`] | a plain 3D vector, like a velocity | metres, m/s |
//!
//! A few rules hold everywhere:
//!
//! - Latitude comes first: `Geodetic::new(lat, lon, height)`.
//! - Bearings go clockwise from north, from 0Β° to 360Β°.
//! - Heights are above the WGS84 ellipsoid, like GPS. They are not heights above sea level.
//! - [`WGS84`] is the default, but any [`Ellipsoid`] works: `GRS80.to_ecef(p)`.
//! - A few low-level helpers use radians, and their names say so (`lat_rad`, `gmst_rad`).
//! [`Vec3::angle_to`] also returns radians.
//!
//! # π§ Find what you need
//!
//! | I want to⦠| Use |
//! |---|---|
//! | convert between latitude/longitude and x, y, z | [`geodetic_to_ecef`], [`ecef_to_geodetic`] |
//! | find where something is, relative to me | [`LocalFrame::enu_of`], [`LocalFrame::ned_of`] |
//! | work out which way to point, and back | [`LocalFrame::look_angles`], [`LocalFrame::destination`] |
//! | find where a line of sight hits the ground | [`ground_strike`], [`Ellipsoid::ray_intersect`] |
//! | measure a straight line through space | [`distance3d_m`] |
//! | measure distance along the ground | [`Ellipsoid::geodesic_inverse`] (exact), [`Ellipsoid::great_circle_distance_m`] (quick) |
//! | travel a distance on a bearing | [`Ellipsoid::geodesic_direct`], [`Ellipsoid::great_circle_destination`] |
//! | check if something is inside a zone | [`Sphere`], [`Cone`], [`Cylinder`], [`AltitudeBand`] (all are [`Volume`]s) |
//! | check if two objects will collide | [`Track::conflict`], [`closest_approach`] |
//! | turn a velocity into heading, speed and climb | [`Course`], [`LocalFrame::course_of_velocity`] |
//! | check line of sight, or how far I can see | [`Ellipsoid::line_of_sight`], [`Ellipsoid::horizon_distance_m`] |
//! | track satellites | the [`eci`] module |
//! | shift between datums | [`Helmert7`] |
//!
//! More worked examples, a comparison with other crates and an accuracy table are in the
//! [README](https://github.com/FusionVault/geo3d#readme).
//!
//! # π§© Optional features
//!
//! They're all off by default, so a plain `cargo add geo3d` pulls in nothing else.
//!
//! | Feature | What it adds |
//! |---|---|
//! | `serde` | saving and loading every type |
//! | `mint` | conversions to `mint` types, and through them to `cgmath` and others |
//! | `glam` | conversions to `glam::DVec3` |
//! | `nalgebra` | conversions to `nalgebra` vectors and points |
//! | `geo-types` | [`Geodetic`] β `geo_types::Point` (x is longitude, y is latitude) |
/// Every Rust code block in the README is compiled and run as a doctest.
;
pub use Helmert7;
pub use ;
pub use LocalFrame;
pub use Geodesic;
pub use ;
pub use ;
pub use ;
pub use Vec3;
pub use ;
/// Latitude/longitude/height β x, y, z on [`WGS84`]. Shorthand for [`WGS84.to_ecef`](Ellipsoid::to_ecef).
/// x, y, z β latitude/longitude/height on [`WGS84`]. Shorthand for
/// [`WGS84.to_geodetic`](Ellipsoid::to_geodetic).
/// The straight-line distance between two positions through space, metres β the **slant range**
/// between things at height, not the distance along the surface. On [`WGS84`].
/// Where the line of sight from `observer` along `azimuth_deg` (0 = north, clockwise) and
/// `elevation_deg` (0 = horizon, negative = down) first meets the ground, on [`WGS84`]. `None` if it
/// points into space or the observer is below the surface. Shorthand for
/// [`LocalFrame::ground_strike`].