d3_geo_rs/projection/
equidistant.rs1use 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#[derive(Clone, Debug, Default, PartialEq)]
19pub enum Equidistant {
20 Conic(ConicEquidistant),
22 Equi(Equirectangular<f64>),
24 #[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}