1use crate::proj::{Proj, RA4, RA6, SIXTH};
2use libm::{asin, cos, sin, sqrt, tan};
3
4pub fn derive_sphere(proj: &mut Proj) {
9 if proj.a == 0.0 {
10 let ellipse = get_ellipsoid(&proj.ellps).unwrap_or(WGS84);
12 proj.a = ellipse.a;
13 if let Some(b) = ellipse.b {
14 proj.b = b;
15 }
16 if let Some(rf) = ellipse.rf {
17 proj.rf = rf;
18 }
19 }
20 if proj.b == 0.0 && proj.rf != 0.0 {
21 proj.b = (1. - 1. / proj.rf) * proj.a;
22 }
23 if proj.b != 0.0 && proj.rf == 0.0 {
24 let a = proj.a;
25 let b = proj.b;
26 proj.rf = (a - b) / a;
27 }
28 let rf = proj.rf;
29 let a = proj.a;
30 if rf == 0.0 || (proj.b != 0.0 && (a - proj.b).abs() < f64::EPSILON) {
31 proj.sphere = true;
32 proj.b = proj.a;
33 }
34
35 derive_eccentricity(proj);
36}
37
38pub fn derive_eccentricity(proj: &mut Proj) {
43 let mut a = proj.a;
44 let b = proj.b;
45 let mut a2 = a * a; let b2 = b * b; let mut es = (a2 - b2) / a2; let mut e = 0.0;
49 if proj.sphere {
50 a *= 1. - es * (SIXTH + es * (RA4 + es * RA6));
51 a2 = a * a;
52 es = 0.;
53 } else {
54 e = sqrt(es); }
56 proj.a = a;
57 proj.b = b;
58 proj.es = es;
59 proj.e = e;
60
61 let alpha = asin(e);
63 proj.alpha = alpha;
64
65 proj.e2 = tan(alpha);
67 proj.e2s = proj.e2 * proj.e2;
68
69 let sin_alpha = sin(alpha);
70 proj.e3 = if alpha != 0.0 { sin_alpha / sqrt(2.0 - sin_alpha * sin_alpha) } else { 0.0 };
71 proj.e3s = proj.e3 * proj.e3;
72
73 let cos_alpha = cos(alpha);
75 proj.f = 1. - cos_alpha;
76 proj.rf = if proj.f != 0.0 { 1. / proj.f } else { f64::INFINITY };
77 proj.f2 = if cos_alpha != 0.0 { 1. / cos_alpha - 1. } else { 0.0 };
78 proj.rf2 = if proj.f2 != 0.0 { 1. / proj.f2 } else { f64::INFINITY };
79
80 proj.n = (a - b) / (a + b);
82 proj.rn = if proj.n != 0.0 { 1. / proj.n } else { f64::INFINITY };
83
84 proj.ra = 1. / a;
86 proj.rb = 1. / b;
87
88 proj.one_es = 1. - es;
90 if proj.one_es == 0.0 {
91 return;
93 }
94 proj.rone_es = 1. / proj.one_es;
95
96 proj.e2 = (a2 - b2) / b2;
98}
99
100#[derive(Debug)]
102pub struct Ellipsoidal {
103 pub a: f64,
105 pub b: Option<f64>,
107 pub rf: Option<f64>,
109}
110
111pub const CGCS2000: Ellipsoidal = Ellipsoidal { a: 6_378_137.0, b: None, rf: Some(298.257222101) };
113
114pub const GSK_2011: Ellipsoidal = Ellipsoidal { a: 6_378_136.5, b: None, rf: Some(298.2564151) };
116
117pub const ZACH: Ellipsoidal = Ellipsoidal { a: 6_376_045.0, b: None, rf: Some(310.0) };
119
120pub const AIRY: Ellipsoidal = Ellipsoidal { a: 6_377_563.396, b: None, rf: Some(299.3249646) };
122
123pub const MOD_AIRY: Ellipsoidal = Ellipsoidal { a: 6_377_340.189, b: None, rf: Some(299.3249646) };
125
126pub const AUST_SA: Ellipsoidal = Ellipsoidal { a: 6_378_160.0, b: None, rf: Some(298.25) };
128
129pub const BESSEL: Ellipsoidal = Ellipsoidal { a: 6_377_397.155, b: None, rf: Some(299.1528128) };
131
132pub const MOD_BESSEL: Ellipsoidal = Ellipsoidal { a: 6_377_390.0, b: None, rf: Some(299.1528128) };
134
135pub const CLRK58: Ellipsoidal =
137 Ellipsoidal { a: 6_378_293.645_208_759, b: Some(6_356_617.987_679_838), rf: None };
138
139pub const CLRK66: Ellipsoidal = Ellipsoidal { a: 6_378_206.4, b: Some(6_356_583.8), rf: None };
141
142pub const CLRK80BEN: Ellipsoidal =
144 Ellipsoidal { a: 6_378_300.789, b: Some(6_356_566.435), rf: None };
145
146pub const CLRK80IGN: Ellipsoidal = Ellipsoidal { a: 6378249.2, b: Some(6356515.0), rf: None };
148
149pub const CLRK80RGS: Ellipsoidal = Ellipsoidal { a: 6_378_249.145, b: None, rf: Some(293.465) };
151
152pub const CLRK80ARC: Ellipsoidal = Ellipsoidal { a: 6_378_249.145, b: None, rf: Some(293.4663077) };
154
155pub const CLRK80SGA: Ellipsoidal = Ellipsoidal { a: 6_378_249.2, b: None, rf: Some(293.46598) };
157
158pub const EVRST30: Ellipsoidal = Ellipsoidal { a: 6_377_276.345, b: None, rf: Some(300.8017) };
160
161pub const EVRSTSS: Ellipsoidal = Ellipsoidal { a: 6_377_298.556, b: None, rf: Some(300.8017) };
163
164pub const EVRST67: Ellipsoidal = EVRSTSS;
166
167pub const EVRST48: Ellipsoidal = Ellipsoidal { a: 6_377_304.063, b: None, rf: Some(300.8017) };
169
170pub const EVRST30_MOD: Ellipsoidal = EVRST48;
172
173pub const GRS80: Ellipsoidal = Ellipsoidal { a: 6_378_137.0, b: None, rf: Some(298.257222101) };
175
176pub const HELMERT: Ellipsoidal = Ellipsoidal { a: 6_378_200.0, b: None, rf: Some(298.3) };
178
179pub const INDONESIAN: Ellipsoidal = Ellipsoidal { a: 6_378_160.0, b: None, rf: Some(298.247) };
181
182pub const INTL24: Ellipsoidal = Ellipsoidal { a: 6_378_388.0, b: None, rf: Some(297.0) };
184
185pub const KRASS: Ellipsoidal = Ellipsoidal { a: 6_378_245.0, b: None, rf: Some(298.3) };
187
188pub const NWL9D: Ellipsoidal = Ellipsoidal { a: 6_378_145.0, b: None, rf: Some(298.25) };
190
191pub const NWL10D: Ellipsoidal = NWL9D;
193
194pub const PLESSIS: Ellipsoidal = Ellipsoidal { a: 6_376_523.0, b: None, rf: Some(308.64) };
196
197pub const STRUVE: Ellipsoidal = Ellipsoidal { a: 6_378_298.3, b: None, rf: Some(294.73) };
199
200pub const WARO: Ellipsoidal = Ellipsoidal { a: 6_378_300.0, b: None, rf: Some(296.0) };
202
203pub const WGS84: Ellipsoidal = Ellipsoidal { a: 6_378_137.0, b: None, rf: Some(298.257223563) };
205
206pub const GEM10C: Ellipsoidal = WGS84;
208
209pub const OSU86F: Ellipsoidal = Ellipsoidal { a: 6_378_136.2, b: None, rf: Some(298.257223563) };
211
212pub const OSU91A: Ellipsoidal = Ellipsoidal { a: 6_378_136.3, b: None, rf: Some(298.257223563) };
214
215pub const CLRK80: Ellipsoidal =
217 Ellipsoidal { a: 6_378_249.144_808_011, b: Some(6_356_514.966204133), rf: None };
218
219pub const GRS67: Ellipsoidal = Ellipsoidal { a: 6_378_160.0, b: None, rf: Some(298.247167427) };
221
222pub const ATS77: Ellipsoidal = Ellipsoidal { a: 6_378_135.0, b: None, rf: Some(298.257) };
224
225pub const EVRST1830: Ellipsoidal =
227 Ellipsoidal { a: 6_377_299.365_595_443, b: Some(6_356_098.359_005_22), rf: None };
228
229pub const WGS7: Ellipsoidal = Ellipsoidal { a: 6_378_135.0, b: None, rf: Some(298.26) };
231
232pub const EVRST62: Ellipsoidal = Ellipsoidal { a: 6_377_301.243, b: None, rf: Some(300.8017255) };
234
235pub const EVRST75: Ellipsoidal = Ellipsoidal { a: 6_377_299.151, b: None, rf: Some(300.8017255) };
237
238pub const BESS_NAM: Ellipsoidal =
240 Ellipsoidal { a: 6_377_483.865280418, b: None, rf: Some(299.1528128) };
241
242pub const GRS80_AUTH: Ellipsoidal = Ellipsoidal { a: 6_371_007.0, b: Some(6_371_007.0), rf: None };
246
247pub const IAG75: Ellipsoidal = Ellipsoidal { a: 6_378_140.0, b: None, rf: Some(298.257) };
249
250pub const GRS_MOD: Ellipsoidal = Ellipsoidal { a: 6_378_160.0, b: None, rf: Some(298.25) };
252
253pub const DANISH: Ellipsoidal = Ellipsoidal { a: 6_377_019.27, b: None, rf: Some(300.0) };
255
256pub const CLRK_AUTH: Ellipsoidal = Ellipsoidal { a: 6_370_997.0, b: Some(6_370_997.0), rf: None };
260
261pub const HOUGH: Ellipsoidal = Ellipsoidal { a: 6_378_270.0, b: None, rf: Some(297.0) };
263
264pub const PZ90: Ellipsoidal = Ellipsoidal { a: 6_378_136.0, b: None, rf: Some(298.257839303) };
266
267pub const CLRK80FOOT: Ellipsoidal =
269 Ellipsoidal { a: 6_378_306.369_6, b: Some(6_356_571.996), rf: None };
270
271pub const EVRST_RSO: Ellipsoidal = Ellipsoidal { a: 6_377_295.664, b: None, rf: Some(300.8017) };
273
274pub const INTL1924_AUTH: Ellipsoidal =
278 Ellipsoidal { a: 6_371_228.0, b: Some(6_371_228.0), rf: None };
279
280pub const HUGHES: Ellipsoidal = Ellipsoidal { a: 6_378_273.0, b: Some(6_356_889.449), rf: None };
282
283pub const MERIT: Ellipsoidal = Ellipsoidal { a: 6_378_137.0, b: None, rf: Some(298.257) };
287
288pub const SGS85: Ellipsoidal = Ellipsoidal { a: 6_378_136.0, b: None, rf: Some(298.257) };
290
291pub const IAU76: Ellipsoidal =
293 Ellipsoidal { a: 6_378_140.0, b: Some(6_356_755.29), rf: Some(298.257) };
294
295pub const APL4: Ellipsoidal = Ellipsoidal { a: 6_378_137.0, b: None, rf: Some(298.25) };
297
298pub const ANDRAE: Ellipsoidal = Ellipsoidal { a: 6_377_104.43, b: None, rf: Some(300.0) };
300
301pub const CLRK80MICH: Ellipsoidal =
303 Ellipsoidal { a: 6_378_450.0475489, b: Some(6_356_826.62148844), rf: None };
304
305pub const CPM: Ellipsoidal = Ellipsoidal { a: 6_375_738.7, b: None, rf: Some(334.29) };
307
308pub const DELMBR: Ellipsoidal = Ellipsoidal { a: 6_376_428.0, b: None, rf: Some(311.5) };
310
311pub const ENGELIS: Ellipsoidal = Ellipsoidal { a: 6_378_136.05, b: None, rf: Some(298.2566) };
313
314pub const EVRST56: Ellipsoidal = Ellipsoidal { a: 6_377_301.243, b: None, rf: Some(300.8017) };
316
317pub const EVRST69: Ellipsoidal = Ellipsoidal { a: 6_377_295.664, b: None, rf: Some(300.8017) };
319
320pub const FSCHR60: Ellipsoidal = Ellipsoidal { a: 6_378_166.0, b: None, rf: Some(298.3) };
322
323pub const FSCHR60M: Ellipsoidal = Ellipsoidal { a: 6_378_155.0, b: None, rf: Some(298.3) };
325
326pub const FSCHR68: Ellipsoidal = Ellipsoidal { a: 6_378_150.0, b: None, rf: Some(298.3) };
328
329pub const INTL: Ellipsoidal = Ellipsoidal { a: 6_378_388.0, b: None, rf: Some(297.0) };
331
332pub const INTL09: Ellipsoidal = INTL;
334
335pub const INTL67: Ellipsoidal = AUST_SA;
337
338pub const KAULA: Ellipsoidal = Ellipsoidal { a: 6_378_163.0, b: None, rf: Some(298.24) };
340
341pub const LERCH: Ellipsoidal = Ellipsoidal { a: 6_378_139.0, b: None, rf: Some(298.257) };
343
344pub const MPRTS: Ellipsoidal = Ellipsoidal { a: 6_397_300.0, b: None, rf: Some(191.0) };
346
347pub const NEW_INTL: Ellipsoidal = Ellipsoidal { a: 6_378_157.5, b: Some(6_356_772.2), rf: None };
349
350pub const SEASIA: Ellipsoidal = Ellipsoidal { a: 6_378_155.0, b: Some(6_356_773.320_5), rf: None };
352
353pub const WALBECK: Ellipsoidal = Ellipsoidal { a: 6_376_896.0, b: Some(6_355_834.846_7), rf: None };
355
356pub const WGS60: Ellipsoidal = Ellipsoidal { a: 6_378_165.0, b: None, rf: Some(298.3) };
358
359pub const WGS66: Ellipsoidal = Ellipsoidal { a: 6_378_145.0, b: None, rf: Some(298.25) };
361
362pub const SPHERE: Ellipsoidal = Ellipsoidal { a: 6_370_997.0, b: Some(6_370_997.0), rf: None };
364
365#[cfg_attr(feature = "nightly", coverage(off))]
367pub fn get_ellipsoid_from_id(id: i64) -> Option<Ellipsoidal> {
368 match id {
369 1024 => Some(CGCS2000),
370 1025 => Some(GSK_2011),
371 1026 => Some(ZACH),
372 7001 => Some(AIRY),
373 7002 => Some(MOD_AIRY),
374 7003 => Some(AUST_SA),
375 7004 => Some(BESSEL),
376 7005 => Some(MOD_BESSEL),
377 7007 => Some(CLRK58),
378 7008 => Some(CLRK66),
379 7010 => Some(CLRK80BEN),
380 7011 => Some(CLRK80IGN),
381 7012 => Some(CLRK80RGS),
382 7013 => Some(CLRK80ARC),
383 7014 => Some(CLRK80SGA),
384 7015 => Some(EVRST30),
385 7016 => Some(EVRST67),
386 7018 => Some(EVRST30_MOD),
387 7019 => Some(GRS80),
388 7020 => Some(HELMERT),
389 7021 => Some(INDONESIAN),
390 7022 => Some(INTL24),
391 7024 => Some(KRASS),
392 7025 => Some(NWL9D),
393 7027 => Some(PLESSIS),
394 7028 => Some(STRUVE),
395 7029 => Some(WARO),
396 7030 => Some(WGS84),
397 7031 => Some(GEM10C),
398 7032 => Some(OSU86F),
399 7033 => Some(OSU91A),
400 7034 => Some(CLRK80),
401 7036 => Some(GRS67),
402 7041 => Some(ATS77),
403 7042 => Some(EVRST1830),
404 7043 => Some(WGS7),
405 7044 => Some(EVRST62),
406 7045 => Some(EVRST75),
407 7046 => Some(BESS_NAM),
408 7048 => Some(GRS80_AUTH),
409 7049 => Some(IAG75),
410 7050 => Some(GRS_MOD),
411 7051 => Some(DANISH),
412 7052 => Some(CLRK_AUTH),
413 7053 => Some(HOUGH),
414 7054 => Some(PZ90),
415 7055 => Some(CLRK80FOOT),
416 7056 => Some(EVRST_RSO),
417 7057 => Some(INTL1924_AUTH),
418 7058 => Some(HUGHES),
419 _ => None,
420 }
421}
422
423#[cfg_attr(feature = "nightly", coverage(off))]
425pub fn get_ellipsoid(name: &str) -> Option<Ellipsoidal> {
426 let name = name.to_uppercase().replace("_", "");
428 match name.as_str() {
429 "AIRY" => Some(AIRY),
430 "APL4" => Some(APL4),
431 "NWL9D" => Some(NWL9D),
432 "NWL10D" => Some(NWL10D),
433 "MODAIRY" => Some(MOD_AIRY),
434 "ANDRAE" => Some(ANDRAE),
435 "AUSTSA" => Some(AUST_SA),
436 "GRS67" => Some(GRS67),
437 "BESSEL" => Some(BESSEL),
438 "MODBESSEL" => Some(MOD_BESSEL),
439 "BESSNAM" => Some(BESS_NAM),
440 "CLRK58" => Some(CLRK58),
441 "CLRK66" => Some(CLRK66),
442 "CLRK80" => Some(CLRK80),
443 "CLRK80MICH" => Some(CLRK80MICH),
444 "CLRK80BEN" => Some(CLRK80BEN),
445 "CLRK80IGN" => Some(CLRK80IGN),
446 "CLRK80RGS" => Some(CLRK80RGS),
447 "CLRK80ARC" => Some(CLRK80ARC),
448 "CLRK80SGA" => Some(CLRK80SGA),
449 "CPM" => Some(CPM),
450 "DELMBR" => Some(DELMBR),
451 "ENGLIS" => Some(ENGELIS),
452 "EVRST30" => Some(EVRST30),
453 "EVRST48" => Some(EVRST48),
454 "EVRST30MOD" => Some(EVRST30_MOD),
455 "EVRST56" => Some(EVRST56),
456 "EVRSTSS" => Some(EVRSTSS),
457 "EVRST67" => Some(EVRST67),
458 "EVRST69" => Some(EVRST69),
459 "EVRST75" => Some(EVRST75),
460 "FSCHR60" => Some(FSCHR60),
461 "FSCHR60M" => Some(FSCHR60M),
462 "FSCHR68" => Some(FSCHR68),
463 "GEM10C" => Some(GEM10C),
464 "GRS80" => Some(GRS80),
465 "HELMERT" => Some(HELMERT),
466 "HOUGH" => Some(HOUGH),
467 "IAU76" => Some(IAU76),
468 "INDONESIAN" => Some(INDONESIAN),
469 "INTL" => Some(INTL),
470 "INTL09" => Some(INTL09),
471 "INTL24" => Some(INTL24),
472 "INTL67" => Some(INTL67),
473 "KAULA" => Some(KAULA),
474 "LERCH" => Some(LERCH),
475 "MPRTS" => Some(MPRTS),
476 "NEWINTL" => Some(NEW_INTL),
477 "PLESSIS" => Some(PLESSIS),
478 "KRASS" => Some(KRASS),
479 "SEASIA" => Some(SEASIA),
480 "STRUVE" => Some(STRUVE),
481 "MERIT" => Some(MERIT),
482 "SGS85" => Some(SGS85),
483 "OSU86F" => Some(OSU86F),
484 "OSU91A" => Some(OSU91A),
485 "WGS66" => Some(WGS66),
486 "WGS7" => Some(WGS7),
487 "WGS84" => Some(WGS84),
488 "WGS60" => Some(WGS60),
489 "SPHERE" => Some(SPHERE),
490 "WARO" => Some(WARO),
491 "WALBECK" => Some(WALBECK),
492 _ => None,
493 }
494}