Skip to main content

geometry_cs/
system.rs

1//! The [`CoordinateSystem`] trait and its four concrete types.
2//!
3//! Mirrors the `cs::{cartesian,spherical,geographic,polar}` empty /
4//! `<Unit>`-parameterised tag types in
5//! `boost/geometry/core/cs.hpp:85-165`, together with the
6//! `traits::cs_tag<Cs>` family classifier at `cs.hpp:194-225`.
7//!
8//! The `Family` associated type is the Rust analogue of Boost's
9//! `cs_tag<Cs>::type`. Algorithm bounds key on the family
10//! (`<P::Cs as CoordinateSystem>::Family`) so a strategy written for
11//! `SphericalFamily` automatically applies to both
12//! `Spherical<Degree>` and `Spherical<Radian>`.
13
14use core::marker::PhantomData;
15
16use crate::family::{CartesianFamily, GeographicFamily, PolarFamily, SphericalFamily};
17use crate::unit::AngleUnit;
18
19/// A coordinate system.
20///
21/// Mirrors `traits::coordinate_system<Point>::type` from
22/// `boost/geometry/core/coordinate_system.hpp:43-49`: the typedef every
23/// point exposes that identifies *which* coordinate system its values
24/// live in. The `Family` associated type is the analogue of Boost's
25/// `traits::cs_tag<Cs>::type` (`cs.hpp:186-225`), the family-level
26/// classifier that strategies actually dispatch on.
27///
28/// # Examples
29///
30/// ```
31/// use geometry_cs::{Cartesian, CartesianFamily, CoordinateSystem};
32/// // Every CS exposes its `Family`; strategies bind on the family.
33/// fn _cartesian_family<C: CoordinateSystem<Family = CartesianFamily>>() {}
34/// _cartesian_family::<Cartesian>();
35/// ```
36pub trait CoordinateSystem {
37    /// The CS family this concrete system belongs to.
38    ///
39    /// Mirrors `boost::geometry::traits::cs_tag<Cs>::type`
40    /// (`boost/geometry/core/cs.hpp:194-225`).
41    type Family;
42}
43
44/// Cartesian / rectangular coordinates.
45///
46/// Mirrors `boost::geometry::cs::cartesian`
47/// (`boost/geometry/core/cs.hpp:85-93`).
48///
49/// # Examples
50///
51/// ```
52/// use geometry_cs::{Cartesian, CartesianFamily, CoordinateSystem};
53/// let _: <Cartesian as CoordinateSystem>::Family = CartesianFamily;
54/// ```
55#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
56pub struct Cartesian;
57
58impl CoordinateSystem for Cartesian {
59    type Family = CartesianFamily;
60}
61
62/// Spherical coordinates in unit `U`.
63///
64/// Mirrors `boost::geometry::cs::spherical<DegreeOrRadian>`
65/// (`boost/geometry/core/cs.hpp:115-135`).
66///
67/// # Convention: latitude measured from the equator
68///
69/// Boost has *two* spherical tags
70/// (`boost/geometry/core/tags.hpp:38-41`):
71///
72/// * `spherical_polar_tag` — colatitude. The second coordinate is
73///   the angle from the **pole**, ranging `[0, π]`.
74/// * `spherical_equatorial_tag` — latitude. The second coordinate
75///   is the angle from the **equator**, ranging `[-π/2, π/2]`.
76///
77/// v1 collapses both into one [`Spherical<U>`] family and picks the
78/// **equatorial** convention because that is what the OGC standard
79/// and the Boost.Geometry quickstart use
80/// (`doc/src/examples/quick_start.cpp` Amsterdam → Paris example).
81///
82/// In coordinate order:
83///
84/// ```text
85/// get::<0>(p)  →  longitude (azimuth, around the polar axis)
86/// get::<1>(p)  →  latitude  (measured from the equator)
87/// ```
88///
89/// In a `Spherical<Degree>` point, longitude ranges `-180.0..=180.0`
90/// (east of Greenwich is positive) and latitude ranges
91/// `-90.0..=90.0` (north of the equator is positive). Amsterdam
92/// (≈ 4.90° E, 52.37° N) is `(4.90, 52.37)` — the "north of the
93/// equator" component is the *second* coordinate.
94///
95/// # If you have colatitude data
96///
97/// Convert to latitude first: `latitude = 90° − colatitude`
98/// (degrees) or `π/2 − colatitude` (radians). The dedicated
99/// `SphericalPolar` / `SphericalEquatorial` split is deferred — see
100/// `specs/FUTURE_ITERATIONS.md` §1.2.
101///
102/// # Examples
103///
104/// ```
105/// use geometry_cs::{CoordinateSystem, Degree, Spherical, SphericalFamily};
106/// fn _spherical<C: CoordinateSystem<Family = SphericalFamily>>() {}
107/// _spherical::<Spherical<Degree>>();
108/// ```
109#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
110pub struct Spherical<U: AngleUnit>(PhantomData<U>);
111
112impl<U: AngleUnit> CoordinateSystem for Spherical<U> {
113    type Family = SphericalFamily;
114}
115
116/// Geographic (lat / lon) coordinates on a spheroid in unit `U`.
117///
118/// Mirrors `boost::geometry::cs::geographic<DegreeOrRadian>`
119/// (`boost/geometry/core/cs.hpp:98-110`).
120///
121/// # Convention: latitude measured from the equator
122///
123/// Same equatorial convention as [`Spherical<U>`] — the difference
124/// is the *earth model*: `Geographic` distances run on a spheroid
125/// (Andoyer / Vincenty / Thomas), `Spherical` on a perfect sphere
126/// (Haversine). In coordinate order:
127///
128/// ```text
129/// get::<0>(p)  →  longitude (east of Greenwich positive)
130/// get::<1>(p)  →  latitude  (north of the equator positive)
131/// ```
132///
133/// In a `Geographic<Degree>` point, longitude ranges `-180.0..=180.0`
134/// and latitude ranges `-90.0..=90.0`.
135///
136/// # Examples
137///
138/// ```
139/// use geometry_cs::{CoordinateSystem, Degree, Geographic, GeographicFamily};
140/// fn _geo<C: CoordinateSystem<Family = GeographicFamily>>() {}
141/// _geo::<Geographic<Degree>>();
142/// ```
143#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
144pub struct Geographic<U: AngleUnit>(PhantomData<U>);
145
146impl<U: AngleUnit> CoordinateSystem for Geographic<U> {
147    type Family = GeographicFamily;
148}
149
150/// Polar coordinates in unit `U`.
151///
152/// Mirrors `boost::geometry::cs::polar<DegreeOrRadian>`
153/// (`boost/geometry/core/cs.hpp:155-165`).
154///
155/// # Examples
156///
157/// ```
158/// use geometry_cs::{CoordinateSystem, Polar, PolarFamily, Radian};
159/// fn _polar<C: CoordinateSystem<Family = PolarFamily>>() {}
160/// _polar::<Polar<Radian>>();
161/// ```
162#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
163pub struct Polar<U: AngleUnit>(PhantomData<U>);
164
165impl<U: AngleUnit> CoordinateSystem for Polar<U> {
166    type Family = PolarFamily;
167}