gistools/proj/project/
vandg.rs1use crate::proj::{CoordinateStep, Proj, ProjectCoordinates, TransformCoordinates};
2use alloc::rc::Rc;
3use core::{
4 cell::RefCell,
5 f64::consts::{FRAC_PI_2, PI, TAU},
6};
7use libm::{acos, asin, cos, fabs, sqrt, tan};
8
9const TOL: f64 = 1e-10;
11const THIRD: f64 = 0.333_333_333_333_333_3;
12const C2_27: f64 = 0.074_074_074_074_074_07; const PI4_3: f64 = 4.188_790_204_786_391; const PISQ: f64 = 9.869_604_401_089_358; const TPISQ: f64 = 19.739_208_802_178_716; const HPISQ: f64 = 4.934_802_200_544_679; #[derive(Debug, Clone, PartialEq)]
50pub struct VanDerGrintenIProjection {
51 proj: Rc<RefCell<Proj>>,
52}
53impl ProjectCoordinates for VanDerGrintenIProjection {
54 fn code(&self) -> i64 {
55 -1
56 }
57 fn name(&self) -> &'static str {
58 "van der Grinten (I)"
59 }
60 fn names() -> &'static [&'static str] {
61 &["van der Grinten", "VanDerGrinten", "Van_der_Grinten_I", "van der Grinten (I)", "vandg"]
62 }
63}
64impl CoordinateStep for VanDerGrintenIProjection {
65 fn new(proj: Rc<RefCell<Proj>>) -> Self {
66 {
67 let proj = &mut proj.borrow_mut();
68 proj.es = 0.;
69 }
70 VanDerGrintenIProjection { proj }
71 }
72 fn forward<P: TransformCoordinates>(&self, p: &mut P) {
73 vandg_s_forward(&self.proj.borrow(), p);
74 }
75 fn inverse<P: TransformCoordinates>(&self, p: &mut P) {
76 vandg_s_inverse(p);
77 }
78}
79
80pub fn vandg_s_forward<P: TransformCoordinates>(proj: &Proj, p: &mut P) {
82 let mut x;
84 let mut y;
85 let mut p2 = fabs(p.phi() / FRAC_PI_2); if (p2 - TOL) > 1. {
87 panic!("Coordinate outside projection domain");
88 }
89 let mut sign = 1;
90 if proj.over && fabs(p.lam()) > PI {
91 sign = -1;
92 }
93 if p2 > 1. {
94 p2 = 1.;
95 }
96 if fabs(p.phi()) <= TOL {
97 x = p.lam();
98 y = 0.;
99 } else if fabs(p.lam()) <= TOL || fabs(p2 - 1.) < TOL {
100 x = 0.;
101 y = PI * tan(0.5 * asin(p2));
102 if p.phi() < 0. {
103 y = -y;
104 }
105 } else {
106 let al = 0.5 * (sign as f64) * fabs(PI / p.lam() - p.lam() / PI); let al2 = al * al; let mut g = sqrt(1. - p2 * p2); g = g / (p2 + g - 1.); let g2 = g * g; p2 = g * (2. / p2 - 1.); p2 = p2 * p2; x = g - p2; g = p2 + al2; x = PI * fabs(al * x + sqrt(al2 * x * x - g * (g2 - p2))) / g;
117 if p.lam() < 0. {
118 x = -x;
119 }
120 y = fabs(x / PI);
121 y = 1. - y * (y + 2. * al);
123 if y < -TOL {
124 panic!("Coordinate outside projection domain");
125 }
126 if y < 0. {
127 y = 0.;
128 } else {
129 y = sqrt(y) * (if p.phi() < 0. { -PI } else { PI });
130 }
131 }
132
133 p.set_x(x);
134 p.set_y(y);
135}
136
137pub fn vandg_s_inverse<P: TransformCoordinates>(p: &mut P) {
139 let x2 = p.x() * p.x(); let ay = fabs(p.y());
145 if ay < TOL {
146 p.set_phi(0.);
147 let t = x2 * x2 + TPISQ * (x2 + HPISQ);
148 p.set_lam(if fabs(p.x()) <= TOL { 0. } else { 0.5 * (x2 - PISQ + sqrt(t)) / p.x() });
149 return;
150 }
151 let y2 = p.y() * p.y(); let r = x2 + y2; let r2 = r * r; let c1 = -PI * ay * (r + PISQ); let c3 = r2 + TAU * (ay * r + PI * (y2 + PI * (ay + FRAC_PI_2)));
157 let mut c2 = c1 + PISQ * (r - 3. * y2); let c0 = PI * ay; c2 /= c3; let al = c1 / c3 - THIRD * c2 * c2; let m = 2. * sqrt(-THIRD * al); let d = C2_27 * c2 * c2 * c2 + (c0 * c0 - THIRD * c2 * c1) / c3; let al_mul_m = al * m; if fabs(al_mul_m) < 1e-16 {
165 panic!("Coordinate outside projection domain");
166 }
167 let mut d = 3. * d / al_mul_m; let mut t = fabs(d);
169 if (t - TOL) <= 1. {
170 d = if t > 1. { if d > 0. { 0. } else { PI } } else { acos(d) }; if r > PISQ {
172 d = TAU - d;
175 }
176 p.set_phi(PI * (m * cos(d * THIRD + PI4_3) - THIRD * c2));
178 if p.y() < 0. {
179 p.set_phi(-p.phi());
180 }
181 t = r2 + TPISQ * (x2 - y2 + HPISQ);
182 p.set_lam(if fabs(p.x()) <= TOL {
183 0.
184 } else {
185 0.5 * (r - PISQ + (if t <= 0. { 0. } else { sqrt(t) })) / p.x()
186 });
187 } else {
188 panic!("Coordinate outside projection domain");
189 }
190}