d3_geo_rs/projection/
equidistant.rs

1use geo::Coord;
2use num_traits::Zero;
3
4use crate::math::EPSILON;
5use crate::Transform;
6
7use super::builder::types::BuilderAntimeridianResampleNoClip;
8use super::builder_conic::Builder;
9use super::builder_conic::PRConic;
10use super::conic_equidistant::ConicEquidistant;
11use super::equirectangular::Equirectangular;
12use super::BuilderTrait;
13use super::CenterSet;
14use super::RawBase;
15use super::ScaleSet;
16
17/// Projection definition. ``Equidistant::builder()`` returns a builder.
18#[derive(Clone, Debug, Default, PartialEq)]
19pub enum Equidistant {
20    /// Projection depends of values set by `builder_with_phi0_phi1`.
21    Conic(ConicEquidistant),
22    /// Projection depends of values set by `builder_with_phi0_phi1`.
23    Equi(Equirectangular<f64>),
24    /// State before the parallels are set.
25    #[default]
26    Uninitialized,
27}
28
29impl Transform for Equidistant {
30    type T = f64;
31    fn transform(&self, p: &Coord<f64>) -> Coord<f64> {
32        match self {
33            Self::Conic(c) => c.transform(p),
34            Self::Equi(e) => e.transform(p),
35            Self::Uninitialized => Coord {
36                x: f64::NAN,
37                y: f64::NAN,
38            },
39        }
40    }
41
42    #[inline]
43    fn invert(&self, p: &Coord<f64>) -> Coord<f64> {
44        match self {
45            Self::Conic(c) => c.invert(p),
46            Self::Equi(e) => e.invert(p),
47            Self::Uninitialized => Coord {
48                x: f64::NAN,
49                y: f64::NAN,
50            },
51        }
52    }
53}
54
55impl PRConic for Equidistant {
56    fn generate(self, y0: f64, y1: f64) -> Self {
57        let cy0 = y0.cos();
58
59        let diff = y1 - y0;
60        let n = if diff.abs() < EPSILON {
61            y0.sin()
62        } else {
63            (cy0 - y1.cos()) / diff
64        };
65
66        if n.is_zero() {
67            return Self::Equi(Equirectangular::default());
68        }
69
70        let g = cy0 / n + y0;
71        Self::Conic(ConicEquidistant::new(g, n))
72    }
73}
74
75impl RawBase for Equidistant {
76    type Builder<DRAIN: Clone> =
77        Builder<BuilderAntimeridianResampleNoClip<DRAIN, Self, f64>, f64>;
78    #[inline]
79    fn builder<DRAIN: Clone>() -> Self::Builder<DRAIN> {
80        let mut b = Builder::new(Self::default());
81        b.scale_set(131.154_f64).center_set(&Coord {
82            x: 0_f64,
83            y: 13.9389_f64,
84        });
85        b
86    }
87}