gistools/proj/project/
eqdc.rs1use crate::proj::{
2 _msfn, CoordinateStep, EPS10, EQUIDISTANT_CONIC, LATITUDE_OF_FIRST_STANDARD_PARALLEL,
3 LATITUDE_OF_SECOND_STANDARD_PARALLEL, Proj, ProjValue, ProjectCoordinates,
4 TransformCoordinates, enfn, inv_mlfn, mlfn,
5};
6use alloc::{rc::Rc, vec::Vec};
7use core::{cell::RefCell, f64::consts::FRAC_PI_2};
8use libm::{atan2, cos, fabs, hypot, sin};
9
10#[derive(Debug, Default, Clone, PartialEq)]
12pub struct EqdcData {
13 phi1: f64,
14 phi2: f64,
15 n: f64,
16 rho: f64,
17 rho0: f64,
18 c: f64,
19 en: Vec<f64>,
20 ellips: bool,
21}
22
23#[derive(Debug, Clone, PartialEq)]
59pub struct EquidistantConicProjection {
60 proj: Rc<RefCell<Proj>>,
61 store: RefCell<EqdcData>,
62}
63impl ProjectCoordinates for EquidistantConicProjection {
64 fn code(&self) -> i64 {
65 EQUIDISTANT_CONIC
66 }
67 fn name(&self) -> &'static str {
68 "Equidistant Conic"
69 }
70 fn names() -> &'static [&'static str] {
71 &["Equidistant Conic", "Equidistant_Conic", "eqdc"]
72 }
73}
74impl CoordinateStep for EquidistantConicProjection {
75 fn new(proj: Rc<RefCell<Proj>>) -> Self {
76 let mut store = EqdcData::default();
77
78 {
79 let proj = &mut proj.borrow_mut();
80
81 store.phi1 = proj
82 .params
83 .get(&LATITUDE_OF_FIRST_STANDARD_PARALLEL)
84 .unwrap_or(&ProjValue::default())
85 .f64();
86 store.phi2 = proj
87 .params
88 .get(&LATITUDE_OF_SECOND_STANDARD_PARALLEL)
89 .unwrap_or(&ProjValue::default())
90 .f64();
91
92 if fabs(store.phi1) > FRAC_PI_2 {
93 panic!("Invalid value for lat_1: |lat_1| should be <= 90°");
94 }
95
96 if fabs(store.phi2) > FRAC_PI_2 {
97 panic!("Invalid value for lat_2: |lat_2| should be <= 90°");
98 }
99 if fabs(store.phi1 + store.phi2) < EPS10 {
100 panic!("Invalid value for lat_1 and lat_2: |lat_1 + lat_2| should be > 0");
101 }
102
103 store.en = enfn(proj.n);
104
105 let mut sinphi = sin(store.phi1);
106 store.n = sinphi;
107 let mut cosphi = cos(store.phi1);
108 let secant = fabs(store.phi1 - store.phi2) >= EPS10;
109 store.ellips = proj.es > 0.;
110 if store.ellips {
111 let m1 = _msfn(sinphi, cosphi, proj.es);
112 let ml1 = mlfn(store.phi1, sinphi, cosphi, &store.en);
113 if secant {
114 sinphi = sin(store.phi2);
116 cosphi = cos(store.phi2);
117 let ml2 = mlfn(store.phi2, sinphi, cosphi, &store.en);
118 if ml1 == ml2 {
119 panic!("Eccentricity too close to 1");
120 }
121 store.n = (m1 - _msfn(sinphi, cosphi, proj.es)) / (ml2 - ml1);
122 if store.n == 0. {
123 panic!("Invalid value for eccentricity");
125 }
126 }
127 store.c = ml1 + m1 / store.n;
128 store.rho0 = store.c - mlfn(proj.phi0, sin(proj.phi0), cos(proj.phi0), &store.en);
129 } else {
130 if secant {
131 store.n = (cosphi - cos(store.phi2)) / (store.phi2 - store.phi1);
132 }
133 if store.n == 0. {
134 panic!("Invalid value for lat_1 and lat_2: lat_1 + lat_2 should be > 0");
135 }
136 store.c = store.phi1 + cos(store.phi1) / store.n;
137 store.rho0 = store.c - proj.phi0;
138 }
139 }
140
141 EquidistantConicProjection { proj, store: store.into() }
142 }
143 fn forward<P: TransformCoordinates>(&self, p: &mut P) {
144 eqdc_e_forward(&mut self.store.borrow_mut(), p);
145 }
146 fn inverse<P: TransformCoordinates>(&self, p: &mut P) {
147 eqdc_e_inverse(&mut self.store.borrow_mut(), p);
148 }
149}
150
151pub fn eqdc_e_forward<P: TransformCoordinates>(eqdc: &mut EqdcData, p: &mut P) {
153 eqdc.rho = eqdc.c
154 - (if eqdc.ellips { mlfn(p.phi(), sin(p.phi()), cos(p.phi()), &eqdc.en) } else { p.phi() });
155 let lam_mul_n = p.lam() * eqdc.n;
156 p.set_x(eqdc.rho * sin(lam_mul_n));
157 p.set_y(eqdc.rho0 - eqdc.rho * cos(lam_mul_n));
158}
159
160pub fn eqdc_e_inverse<P: TransformCoordinates>(eqdc: &mut EqdcData, p: &mut P) {
162 let mut x = p.x();
163 let mut y = p.y();
164 y = eqdc.rho0 - y;
165 eqdc.rho = hypot(x, y);
166
167 if eqdc.rho != 0.0 {
168 if eqdc.n < 0. {
169 eqdc.rho = -eqdc.rho;
170 x = -x;
171 y = -y;
172 }
173 p.set_phi(eqdc.c - eqdc.rho);
174 if eqdc.ellips {
175 p.set_phi(inv_mlfn(p.phi(), &eqdc.en));
176 }
177 p.set_lam(atan2(x, y) / eqdc.n);
178 } else {
179 p.set_lam(0.);
180 p.set_phi(if eqdc.n > 0. { FRAC_PI_2 } else { -FRAC_PI_2 });
181 }
182}