gistools/proj/project/
gstmerc.rs1use crate::proj::{CoordinateStep, Proj, ProjectCoordinates, TransformCoordinates, phi2, tsfn};
2use alloc::rc::Rc;
3use core::cell::RefCell;
4use libm::{asin, atan, cos, cosh, exp, log, pow, sin, sinh, sqrt};
5
6#[derive(Debug, Default, Clone, PartialEq)]
44pub struct GstmercData {
45 lamc: f64,
46 phic: f64,
47 c: f64,
48 n1: f64,
49 n2: f64,
50 xs: f64,
51 ys: f64,
52}
53
54#[derive(Debug, Clone, PartialEq)]
56pub struct GaussSchreiberTransverseMercatorProjection {
57 proj: Rc<RefCell<Proj>>,
58 store: RefCell<GstmercData>,
59}
60impl ProjectCoordinates for GaussSchreiberTransverseMercatorProjection {
61 fn code(&self) -> i64 {
62 -1
63 }
64 fn name(&self) -> &'static str {
65 "Gauss-Schreiber Transverse Mercator"
66 }
67 fn names() -> &'static [&'static str] {
68 &[
69 "Gauss-Schreiber Transverse Mercator (aka Gauss-Laborde Reunion)",
70 "Gauss-Schreiber Transverse Mercator",
71 "gstmerc",
72 ]
73 }
74}
75impl CoordinateStep for GaussSchreiberTransverseMercatorProjection {
76 fn new(proj: Rc<RefCell<Proj>>) -> Self {
77 let mut store = GstmercData::default();
78 {
79 let proj = proj.borrow();
80 store.lamc = proj.lam0;
81 store.n1 = sqrt(1. + proj.es * pow(cos(proj.phi0), 4.0) / (1. - proj.es));
82 store.phic = asin(sin(proj.phi0) / store.n1);
83 store.c = log(tsfn(-store.phic, -sin(proj.phi0) / store.n1, 0.0))
84 - store.n1 * log(tsfn(-proj.phi0, -sin(proj.phi0), proj.e));
85 store.n2 = proj.k0 * proj.a * sqrt(1. - proj.es)
86 / (1. - proj.es * sin(proj.phi0) * sin(proj.phi0));
87 store.xs = 0.;
88 store.ys = -store.n2 * store.phic;
89 }
90 GaussSchreiberTransverseMercatorProjection { proj, store: store.into() }
91 }
92 fn forward<P: TransformCoordinates>(&self, p: &mut P) {
93 gstmerc_s_forward(&self.store.borrow(), &self.proj.borrow(), p);
94 }
95 fn inverse<P: TransformCoordinates>(&self, p: &mut P) {
96 gstmerc_s_inverse(&self.store.borrow(), &self.proj.borrow(), p);
97 }
98}
99
100pub fn gstmerc_s_forward<P: TransformCoordinates>(gstmerc: &GstmercData, proj: &Proj, p: &mut P) {
102 let l = gstmerc.n1 * p.lam();
103 let ls = gstmerc.c + gstmerc.n1 * log(tsfn(-p.phi(), -sin(p.phi()), proj.e));
104 let sin_ls1 = sin(l) / cosh(ls);
105 let ls1 = log(tsfn(-asin(sin_ls1), -sin_ls1, 0.0));
106 p.set_x((gstmerc.xs + gstmerc.n2 * ls1) * proj.ra);
107 p.set_y((gstmerc.ys + gstmerc.n2 * atan(sinh(ls) / cos(l))) * proj.ra);
108}
109
110pub fn gstmerc_s_inverse<P: TransformCoordinates>(gstmerc: &GstmercData, proj: &Proj, p: &mut P) {
112 let l = atan(
113 sinh((p.x() * proj.a - gstmerc.xs) / gstmerc.n2)
114 / cos((p.y() * proj.a - gstmerc.ys) / gstmerc.n2),
115 );
116 let sin_c = sin((p.y() * proj.a - gstmerc.ys) / gstmerc.n2)
117 / cosh((p.x() * proj.a - gstmerc.xs) / gstmerc.n2);
118 let lc = log(tsfn(-asin(sin_c), -sin_c, 0.0));
119 p.set_lam(l / gstmerc.n1);
120 p.set_phi(-phi2(exp((lc - gstmerc.c) / gstmerc.n1), proj.e));
121}