1pub fn geodetic2ecef(lat: f64, lon: f64, alt: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
17 let n = get_radius_normal(lat, r_ellips);
18 let (major,minor,_,_) = r_ellips.parameters();
19
20 let x = (n + alt) * lat.cos() * lon.cos();
21 let y = (n + alt) * lat.cos() * lon.sin();
22 let z = (n * (minor / major) * (minor / major) + alt) * lat.sin();
23
24 (x,y,z)
25}
26
27pub fn geodetic2aer(lat: f64, lon: f64, alt: f64,lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
43 let (e,n,u) = geodetic2enu(lat,lon,alt,lat0,lon0,alt0,r_ellips);
44 let (az,el,slant_range) = enu2aer(e, n, u);
45
46 (az,el,slant_range)
47}
48
49pub fn geodetic2enu(lat: f64, lon: f64, alt: f64,lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
65 let (x1,y1,z1) = geodetic2ecef(lat, lon, alt, r_ellips);
66 let (x2,y2,z2) = geodetic2ecef(lat0, lon0, alt0, r_ellips);
67
68 let (e,n,u) = uvw2enu(x1-x2, y1-y2, z1-z2, lat0, lon0);
69
70 (e,n,u)
71}
72
73pub fn geodetic2ned(lat: f64, lon: f64, alt: f64,lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
89 let enu = geodetic2enu(lat, lon, alt, lat0, lon0, alt0, r_ellips);
90 (enu.1,enu.0,-enu.2)
91}
92
93pub fn aer2ecef(az : f64, el: f64,slant_range :f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid)-> (f64,f64,f64){
109
110 let (x0,y0,z0) = geodetic2ecef(lat0, lon0, alt0, r_ellips);
111 let (e,n,u) = aer2enu(az,el,slant_range);
112 let (dx,dy,dz) = enu2uvw(e,n,u,lat0,lon0);
113 (x0+dx,y0+dy,z0+dz)
114}
115
116pub fn aer2enu(az : f64, el: f64,slant_range :f64) -> (f64,f64,f64){
128 let r = slant_range*el.cos();
129 (r*az.sin(),r*az.cos(),slant_range*el.sin())
130}
131
132pub fn aer2eci(gst :f64, az : f64, el: f64,slant_range :f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
148 let (x1,y1,z1) = aer2ecef(az, el, slant_range, lat0, lon0, alt0, r_ellips);
149 ecef2eci(gst, x1, y1, z1)
150}
151
152pub fn aer2ned(az : f64, el: f64,slant_range :f64) -> (f64,f64,f64){
164 let enu = aer2enu(az, el, slant_range);
165 (enu.1,enu.0,-enu.2)
166}
167
168pub fn aer2geodetic(az : f64, el: f64,slant_range :f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid)-> (f64,f64,f64) {
184 let (x,y,z) = aer2ecef(az, el, slant_range, lat0, lon0, alt0, r_ellips);
185 ecef2geodetic(x,y,z,r_ellips)
186}
187
188pub fn enu2uvw(et : f64, nt: f64,up :f64, lat0: f64, lon0: f64) -> (f64,f64,f64){
202 let t = lat0.cos()*up - lat0.sin()*nt;
203
204 let u = lon0.cos()*t-lon0.sin()*et;
205 let v = lon0.sin()*t+lon0.cos()*et;
206 let w = lat0.sin()*up+lat0.cos()*nt;
207 (u,v,w)
208}
209
210pub fn enu2aer(e : f64, n: f64,u :f64) -> (f64,f64,f64){
222 let r = (e*e+n*n).sqrt();
223
224 let slant_range = (r*r+u*u).sqrt();
225 let el = u.atan2(r);
226 let az = e.atan2(n).rem_euclid(2.0*std::f64::consts::PI);
227
228 (az,el,slant_range)
229
230}
231
232pub fn enu2ecef(e : f64, n: f64, u: f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
248 let (x0,y0,z0) = geodetic2ecef(lat0, lon0, alt0, r_ellips);
249 let (dx,dy,dz) = enu2uvw(e, n, u, lat0, lon0);
250
251 (x0+dx,y0+dy,z0+dz)
252}
253
254pub fn enu2geodetic(e : f64, n: f64,u :f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
269 let (x,y,z) = enu2ecef(e, n, u, lat0, lon0, alt0, r_ellips);
270 let (lat,lon,alt) = ecef2geodetic(x, y, z, r_ellips);
271
272 (lat,lon,alt)
273}
274
275pub fn ecef2eci(gst :f64,x: f64, y: f64, z: f64) -> (f64,f64,f64){
287 let arr = matmul3(transpose3(r3(gst)),[x,y,z]);
288 (arr[0],arr[1],arr[2])
289
290}
291
292pub fn ecef2geodetic(x: f64, y: f64, z: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
306 let (major, minor, _,_) = r_ellips.parameters();
307
308 let r = (x*x+y*y+z*z).sqrt();
309 let e = (major*major-minor*minor).sqrt();
310 let var = r*r-e*e;
311 let u = (0.5*var+0.5*(var*var+4.0*e*e*z*z).sqrt()).sqrt();
312
313 let q = (x*x+y*y).sqrt();
314 let hu_e = (u*u+e*e).sqrt();
315 let mut beta = (hu_e/u * z/q).atan();
316
317 let eps = ((minor * u - major * hu_e + e*e)*beta.sin())/
318 (major * hu_e/beta.cos() - e*e*beta.cos());
319 beta += eps;
320
321 let lat = (major/minor*beta.tan()).atan();
322 let lon = y.atan2(x);
323
324 let v1 = z - minor * beta.sin();
325 let v2 = q - major*beta.cos();
326 let alt;
327
328 let inside = (x*x/major/major)+(y*y/major/major)+(z*z/minor/minor)<1.0;
329 if inside {
330 alt = -(v1*v1+v2*v2).sqrt();
331 }else {
332 alt = (v1*v1+v2*v2).sqrt();
333 };
334
335 (lat,lon,alt)
336}
337
338pub fn ecef2enu(x: f64, y: f64, z: f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid)-> (f64,f64,f64){
354 let (x0,y0,z0) = geodetic2ecef(lat0, lon0, alt0,r_ellips);
355 let (e,n,u) = uvw2enu(x-x0,y-y0,z-z0,lat0,lon0);
356 (e,n,u)
357}
358
359pub fn ecef2ned(x: f64, y: f64, z: f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid)-> (f64,f64,f64){
375 let enu = ecef2enu(x, y, z, lat0, lon0, alt0, r_ellips);
376 (enu.1,enu.0,-enu.2)
377}
378
379pub fn uvw2enu(u : f64, v: f64,w :f64, lat0: f64, lon0: f64) -> (f64,f64,f64){
393 let t = lon0.cos() * u + lon0.sin() * v;
394 let e = -lon0.sin() * u + lon0.cos() * v;
395 let n = -lat0.sin() * t + lat0.cos() * w;
396 let u = lat0.cos() * t + lat0.sin() * w;
397 (e,n,u)
398}
399
400pub fn ecef2aer(x: f64, y: f64, z: f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid)-> (f64,f64,f64){
416 let (e,n,u) = ecef2enu(x, y, z, lat0, lon0, alt0, r_ellips);
417 let (az,el,slant_range) = enu2aer(e,n,u);
418
419 (az,el,slant_range)
420}
421
422pub fn eci2aer(gst :f64,x: f64, y: f64, z: f64, lat :f64, lon :f64, alt :f64, r_ellips: Ellipsoid)-> (f64,f64,f64){
438 let (x,y,z) = eci2ecef(gst, x, y, z);
439 let (az,el,slant_range) = ecef2aer(x, y, z, lat, lon, alt, r_ellips);
440 (az,el,slant_range)
441}
442
443pub fn eci2ecef(gst :f64,x: f64, y: f64, z: f64)-> (f64,f64,f64){
456 let arr = matmul3(r3(gst),[x,y,z]);
457 (arr[0],arr[1],arr[2])
458}
459
460pub fn ned2aer(n : f64, e: f64,d :f64) -> (f64,f64,f64){
472 let aer = enu2aer(e, n, -d);
473 aer
474}
475
476pub fn ned2geodetic(n : f64, e: f64,d :f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
492 let geo = enu2geodetic(e, n, -d, lat0, lon0, alt0, r_ellips);
493 geo
494}
495
496pub fn ned2ecef(n: f64,e : f64, d :f64, lat0: f64, lon0: f64, alt0: f64, r_ellips: Ellipsoid) -> (f64,f64,f64){
512 let ecef = enu2ecef(e, n, -d, lat0, lon0, alt0, r_ellips);
513 ecef
514}
515
516pub fn matmul3(matrix: [f64;9],col:[f64;3])->[f64;3]{
518 let out : [f64;3] = [ matrix[0]*col[0]+matrix[1]*col[1]+matrix[2]*col[2],
519 matrix[3]*col[0]+matrix[4]*col[1]+matrix[5]*col[2],
520 matrix[6]*col[0]+matrix[7]*col[1]+matrix[8]*col[2]];
521 out
522}
523
524pub fn r3(x : f64) -> [f64; 9] {
526 [x.cos(),x.sin(),0.0,-x.sin(),x.cos(),0.0,0.0,0.0,1.0]
527}
528
529pub fn transpose3(x: [f64;9]) -> [f64;9] {
531 [x[0],x[3],x[6],x[1],x[4],x[7],x[2],x[5],x[8]]
532}
533
534#[derive(Debug, Copy, Clone)]
535pub enum Ellipsoid {
536 WGS84,
540 WGS72,
543 WGS66,
546 WGS60,
549 PZ90,
553 BDC,
559 GRS80,
563 Bessel,
567 Airy,
571 International,
575}
576
577impl Default for Ellipsoid {
578 fn default() -> Ellipsoid {
579 Ellipsoid::WGS84
580 }
581}
582
583impl Ellipsoid {
584 pub fn parameters(&self) -> (f64,f64,f64,f64) {
592 let (major, flattening): (f64, f64) = match self {
593 Ellipsoid::WGS84 => (6378137.0, 1.0/298.257223563),
594 Ellipsoid::WGS72 => (6378135.0, 1.0/298.26),
595 Ellipsoid::WGS66 => (6378145.0, 1.0/298.25),
596 Ellipsoid::WGS60 => (6378165.0, 1.0/298.3),
597 Ellipsoid::PZ90 => (6378136.0, 1.0/298.257839303),
598 Ellipsoid::BDC => (6378137.0, 1.0/298.257222101),
599 Ellipsoid::GRS80 => (6378137.0, 1.0/298.2572221009),
600 Ellipsoid::Bessel =>(6377397.155, 299.1528128),
601 Ellipsoid::Airy => (6377563.396, 299.3249646),
602 Ellipsoid::International => (6378388.0, 297.0),
603 };
604
605 let minor = major * (1.0 - flattening);
606 let ecc_sq = ((major*major)-(minor*minor))/(major*major);
607 (major,minor,flattening,ecc_sq)
608 }
609}
610
611pub fn get_radius_normal(lat: f64, r_ellips: Ellipsoid)->f64 {
614 let (major,_,_,squared_eccentricity) = r_ellips.parameters();
615 major/((1.0-squared_eccentricity*lat.sin()*lat.sin()).sqrt())
616}
617
618pub fn deg2rad(x: f64) -> f64 {
620 x/180.0*std::f64::consts::PI
621}
622
623pub fn rad2deg(x: f64) -> f64 {
625 x*180.0/std::f64::consts::PI
626}
627
628pub fn utc2gst(utc: [i32;6]) -> f64 {
636
637 let mut year = utc[0] as f64;
638 let mut month = utc[1] as f64;
639 let day = utc[2] as f64;
640 let h = utc[3] as f64;
641 let m = utc[4] as f64;
642 let s = utc[5] as f64;
643
644 if month<3.0 {
645 year = year - 1.0;
646 month = month + 12.0;
647 }
648
649 let a = fix(year/100.0);
650
651 let b = 2.0 - a + fix(a/4.0);
652
653 let c = ((s/60.0 + m)/60.0 + h)/24.0;
654
655 let jd = fix(365.25 * (year + 4716.0)) + fix(30.6001*(month + 1.0)) + day + b - 1524.5 + c;
656
657 let t_ut1 = (jd - 2451545.0)/36525.0;
658
659 let gmst_sec = 67310.54841 + 3.164400184812866e+09 * t_ut1 + 0.093104 * t_ut1 * t_ut1
660 - 6.2e-6 * t_ut1 * t_ut1 * t_ut1;
661
662 let gst = (gmst_sec * 2.0 * std::f64::consts::PI / 86400.0).rem_euclid(2.0 * std::f64::consts::PI);
663 gst
664}
665
666pub fn fix(x : f64) -> f64 {
668 let mut out = x;
669 if out<0.0 {
670 out = x.ceil();
671 } else {
672 out = x.floor();
673 }
674 out
675}
676
677pub const EARTH_RADIUS: f64 = 6371E3_f64;
679
680pub fn distance (coord1: (f64,f64), coord2: (f64,f64)) -> f64 {
683 let dphi = deg2rad(coord2.0) - deg2rad(coord1.0);
684 let d_lambda = deg2rad(coord2.1) - deg2rad(coord1.1);
685 let a: f64 = (dphi / 2.0_f64).sin().powf(2.0_f64)
686 + deg2rad(coord1.0).cos() * deg2rad(coord2.0).cos()
687 * (d_lambda/2.0_f64).sin().powf(2.0_f64);
688 let c = 2.0_f64 * a.powf(0.5_f64).atan2((1.0-a).powf(0.5_f64));
689 EARTH_RADIUS * c
690}
691
692#[cfg(test)]
693mod tests {
694 use super::*;
695
696 #[test]
697 fn test_utc2gst() {
698
699 let datetime: [i32;6] = [2020,5,12,18,2,10];
700 let gst_ref = 2.469809475597415;
701
702 let gst = utc2gst(datetime);
703
704 assert!( (gst-gst_ref).abs()<1e-8);
705
706 let datetime2: [i32;6] = [2020,1,12,18,2,10];
707 let gst_ref2 = 0.388271658105431;
708
709 let gst2 = utc2gst(datetime2);
710
711 assert!( (gst2-gst_ref2).abs()<1e-8);
712 }
713
714 #[test]
715 fn test_fix() {
716 let x1 = 3.7;
717 let x2 = -4.67;
718
719 assert_eq!(fix(x1),3.0);
720 assert_eq!(fix(x2),-4.0);
721 }
722
723 #[test]
724 fn test_deg2rad() {
725 assert!((deg2rad(0.0)-0.0).abs()<1e-4);
726 assert!((deg2rad(90.0)-std::f64::consts::PI/2.0).abs()<1e-4);
727 assert!((deg2rad(-90.0)+std::f64::consts::PI/2.0).abs()<1e-4);
728 assert!((deg2rad(45.0)-std::f64::consts::PI/4.0).abs()<1e-4);
729 assert!((deg2rad(270.0)-std::f64::consts::PI*6.0/4.0).abs()<1e-4);
730 assert!((deg2rad(360.0)-std::f64::consts::PI*2.0).abs()<1e-4);
731 }
732
733 #[test]
734 fn test_rad2deg() {
735 assert!((0.0-rad2deg(0.0)).abs()<1e-4);
736 assert!((90.0-rad2deg(std::f64::consts::PI/2.0)).abs()<1e-4);
737 assert!((-90.0+rad2deg(std::f64::consts::PI/2.0)).abs()<1e-4);
738 assert!((45.0-rad2deg(std::f64::consts::PI/4.0)).abs()<1e-4);
739 assert!((270.0-rad2deg(std::f64::consts::PI*6.0/4.0)).abs()<1e-4);
740 assert!((360.0-rad2deg(std::f64::consts::PI*2.0)).abs()<1e-4);
741 }
742
743 #[test]
744 fn test_geodetic2ecef() {
745
746 let lat = deg2rad(30.14988205);
747 let lon = deg2rad(91.38733072);
748 let alt = 4031.0;
749
750 let (x,y,z) = geodetic2ecef(lat,lon,alt, Ellipsoid::default());
751
752 let xref = -1.337281037300386e+05;
753 let yref = 5.521796910920261e+06;
754 let zref = 3.186776473672415e+06;
755
756 assert!((x-xref).abs()<1e-3);
757 assert!((y-yref).abs()<1e-3);
758 assert!((z-zref).abs()<1e-3);
759 }
760
761 #[test]
762 fn test_geodetic2aer() {
763
764 let lat0 = deg2rad(42.0);
765 let lon0 = deg2rad(-82.0);
766 let alt0 = 200.0;
767
768 let lat = deg2rad(42.002581974253744);
769 let lon = deg2rad(-81.997751960067460);
770 let alt = 1.139701799575106e+03;
771
772 let azref = deg2rad(32.999999999989740);
773 let elref = deg2rad(69.999999999945540);
774 let rangeref = 1000.0;
775
776 let (a,e,r) = geodetic2aer(lat, lon, alt, lat0, lon0, alt0, Ellipsoid::default());
777
778 assert!((a-azref).abs()<1e-3);
779 assert!((e-elref).abs()<1e-3);
780 assert!((r-rangeref).abs()<1e-3);
781 }
782
783 #[test]
784 fn test_geodetic2enu() {
785 let lat0 = deg2rad(42.0);
786 let lon0 = deg2rad(-82.0);
787 let alt0 = 200.0;
788
789 let lat = deg2rad(42.002581974253744);
790 let lon = deg2rad(-81.997751960067460);
791 let alt = 1.139701799575106e+03;
792
793 let eref = 1.862775208168244e+02;
794 let nref = 2.868422278521820e+02;
795 let uref = 9.396926207845534e+02;
796
797 let (e,n,u) = geodetic2enu(lat, lon, alt, lat0, lon0, alt0, Ellipsoid::default());
798
799 assert!((e-eref).abs()<1e-3);
800 assert!((n-nref).abs()<1e-3);
801 assert!((u-uref).abs()<1e-3);
802 }
803
804 #[test]
805 fn test_aer2ecef() {
806 let lat0 = deg2rad(42.0);
807 let lon0 = deg2rad(-82.0);
808 let alt0 = 200.0;
809
810 let az = deg2rad(33.0);
811 let el = deg2rad(70.0);
812 let slant_range = 1000.0;
813
814 let (x,y,z) = aer2ecef(az,el,slant_range,lat0,lon0,alt0, Ellipsoid::default());
815
816
817 let xref = 6.609301927610816e+05;
818 let yref = -4.701424222957011e+06;
819 let zref = 4.246579604632881e+06;
820
821 assert!((x-xref).abs()<1e-3);
822 assert!((y-yref).abs()<1e-3);
823 assert!((z-zref).abs()<1e-3);
824 }
825
826 #[test]
827 fn test_aer2enu() {
828 let az = deg2rad(33.0);
829 let el = deg2rad(70.0);
830 let slant_range = 1000.0;
831
832 let eref = 1.862775208165935e+02;
833 let nref = 2.868422278517140e+02;
834 let uref = 9.396926207859083e+02;
835
836 let (e,n,u)= aer2enu(az, el, slant_range);
837
838 assert!((e-eref).abs()<1e-3);
839 assert!((n-nref).abs()<1e-3);
840 assert!((u-uref).abs()<1e-3);
841 }
842
843 #[test]
844 fn test_aer2eci() {
845 let az = deg2rad(162.55);
846 let el = deg2rad(55.12);
847 let slant_range = 384013940.9;
848 let gst = 4.501012562811752;
849
850 let lat0 = deg2rad(28.4);
851 let lon0 = deg2rad(-80.5);
852 let alt0 = 2.7;
853
854 let xref = -3.849714979138141e+08;
855 let yref = -4.836588977863766e+07;
856 let zref = -3.143285462295778e+07;
857
858 let (x,y,z) = aer2eci(gst, az, el, slant_range, lat0, lon0, alt0, Ellipsoid::default());
859
860 assert!((x-xref).abs()<1e-3);
861 assert!((y-yref).abs()<1e-3);
862 assert!((z-zref).abs()<1e-3);
863 }
864
865 #[test]
866 fn test_aer2geodetic() {
867 let lat0 = deg2rad(42.0);
868 let lon0 = deg2rad(-82.0);
869 let alt0 = 200.0;
870
871 let az = deg2rad(32.999999999989740);
872 let el = deg2rad(69.999999999945540);
873 let slant_range = 1000.0;
874
875 let latref = deg2rad(42.002581974253744);
876 let lonref = deg2rad(-81.997751960067460);
877 let altref = 1.139701799575106e+03;
878
879
880 let (lat,lon,alt) = aer2geodetic(az, el, slant_range, lat0, lon0, alt0, Ellipsoid::default());
881
882 assert!((lat-latref).abs()<1e-8);
883 assert!((lon-lonref).abs()<1e-8);
884 assert!((alt-altref).abs()<1e-8);
885 }
886
887 #[test]
888 fn test_enu2aer() {
889 let e = 1.862775210000000e+02;
890 let n = 2.868422200000000e+02;
891 let u = 9.396926200000000e+02;
892
893 let azref = deg2rad(33.0);
894 let elref = deg2rad(70.0);
895 let rangeref = 1000.0;
896
897 let (az,el,range) = enu2aer(e, n, u);
898
899 assert!((az-azref).abs()<1e-3);
900 assert!((el-elref).abs()<1e-3);
901 assert!((range-rangeref).abs()<1e-3);
902 }
903
904 #[test]
905 fn test_enu2ecef() {
906 let lat0 = deg2rad(42.0);
907 let lon0 = deg2rad(-82.0);
908 let alt0 = 200.0;
909 let e = 1.862775210000000e+02;
910 let n = 2.868422200000000e+02;
911 let u = 9.396926200000000e+02;
912
913 let xref = 6.609301927610815e+05;
914 let yref = -4.701424222957011e+06;
915 let zref = 4.246579604632881e+06;
916
917 let (x,y,z) = enu2ecef(e, n, u, lat0, lon0, alt0, Ellipsoid::default());
918
919 assert!((x-xref).abs()<1e-3);
920 assert!((y-yref).abs()<1e-3);
921 assert!((z-zref).abs()<1e-3);
922 }
923
924 #[test]
925 fn test_enu2geodetic() {
926 let lat0 = deg2rad(42.0);
927 let lon0 = deg2rad(-82.0);
928 let alt0 = 200.0;
929 let e = 0.0;
930 let n = 0.0;
931 let u = -1.0;
932
933 let latref = deg2rad(41.999999999999993);
934 let lonref = deg2rad(-82.0);
935 let altref = 1.990000000007368e+02;
936
937 let (lat,lon,alt) = enu2geodetic(e, n, u, lat0, lon0, alt0, Ellipsoid::default());
938
939 assert!((lat-latref).abs()<1e-8);
940 assert!((lon-lonref).abs()<1e-8);
941 assert!((alt-altref).abs()<1e-8);
942 }
943
944 #[test]
945 fn test_ecef2geodetic() {
946 let latref = deg2rad(30.14988205);
947 let lonref = deg2rad(91.38733072);
948 let altref = 4031.0;
949
950 let (x,y,z) = geodetic2ecef(latref, lonref, altref, Ellipsoid::default());
951 let (lat,lon,alt) = ecef2geodetic(x, y, z, Ellipsoid::default());
952
953 assert!((lat-latref).abs()<1e-8);
954 assert!((lon-lonref).abs()<1e-8);
955 assert!((alt-altref).abs()<1e-8);
956
957 let (x,y,z) = geodetic2ecef(latref, lonref, altref-5000.0, Ellipsoid::default());
958 let (lat,lon,alt) = ecef2geodetic(x, y, z, Ellipsoid::default());
959
960 assert!((lat-latref).abs()<1e-8);
961 assert!((lon-lonref).abs()<1e-8);
962 assert!((alt-(altref-5000.0)).abs()<1e-8);
963 }
964
965 #[test]
966 fn test_ecef2enu() {
967 let lat0 = deg2rad(42.0);
968 let lon0 = deg2rad(-82.0);
969 let alt0 = 200.0;
970 let eref = 1.862775210000000e+02;
971 let nref = 2.868422200000000e+02;
972 let uref = 9.396926200000000e+02;
973
974 let (x,y,z) = enu2ecef(eref, nref, uref, lat0, lon0, alt0, Ellipsoid::default());
975 let (e,n,u)= ecef2enu(x, y, z, lat0, lon0, alt0, Ellipsoid::default());
976
977 assert!((e-eref).abs()<1e-3);
978 assert!((n-nref).abs()<1e-3);
979 assert!((u-uref).abs()<1e-3);
980 }
981
982 #[test]
983 fn test_ecef2aer() {
984 let lat0 = deg2rad(42.0);
985 let lon0 = deg2rad(-82.0);
986 let alt0 = 200.0;
987
988 let azref = deg2rad(33.0);
989 let elref = deg2rad(70.0);
990 let rangeref = 1000.0;
991
992 let (x,y,z) = aer2ecef(azref, elref, rangeref, lat0, lon0, alt0, Ellipsoid::default());
993 let (az,el,range) = ecef2aer(x, y, z, lat0, lon0, alt0, Ellipsoid::default());
994
995 assert!((az-azref).abs()<1e-3);
996 assert!((el-elref).abs()<1e-3);
997 assert!((range-rangeref).abs()<1e-3);
998 }
999
1000 #[test]
1001 fn test_eci2aer() {
1002 let azref = deg2rad(162.55);
1003 let elref = deg2rad(55.12);
1004 let rangeref = 384013940.9;
1005 let gst = 4.501012562811752;
1006
1007 let lat0 = deg2rad(28.4);
1008 let lon0 = deg2rad(-80.5);
1009 let alt0 = 2.7;
1010
1011 let (x,y,z) = aer2eci(gst, azref, elref, rangeref, lat0, lon0, alt0, Ellipsoid::default());
1012 let (az,el,range) = eci2aer(gst, x, y, z, lat0, lon0, alt0, Ellipsoid::default());
1013
1014 assert!((az-azref).abs()<1e-3);
1015 assert!((el-elref).abs()<1e-3);
1016 assert!((range-rangeref).abs()<1e-3);
1017 }
1018
1019 #[test]
1020 fn test_ned2geodetic() {
1021 let lat0 = deg2rad(42.0);
1022 let lon0 = deg2rad(-82.0);
1023 let alt0 = 200.0;
1024 let e = 0.0;
1025 let n = 0.0;
1026 let d = 1.0;
1027
1028 let latref = deg2rad(41.999999999999993);
1029 let lonref = deg2rad(-82.0);
1030 let altref = 1.990000000007368e+02;
1031
1032 let (lat,lon,alt) = ned2geodetic(n, e, d, lat0, lon0, alt0, Ellipsoid::default());
1033
1034 assert!((lat-latref).abs()<1e-8);
1035 assert!((lon-lonref).abs()<1e-8);
1036 assert!((alt-altref).abs()<1e-8);
1037 }
1038
1039 #[test]
1040 fn test_geodetic2ned() {
1041 let lat = deg2rad(41.999999999999993);
1042 let lon = deg2rad(-82.0);
1043 let alt = 1.990000000007368e+02;
1044 let lat0 = deg2rad(42.0);
1045 let lon0 = deg2rad(-82.0);
1046 let alt0 = 200.0;
1047
1048 let eref = 0.0;
1049 let nref = 0.0;
1050 let dref = 1.0;
1051
1052 let (n,e,d) = geodetic2ned(lat, lon, alt, lat0, lon0, alt0, Ellipsoid::default());
1053
1054 assert!((e-eref).abs()<1e-3);
1055 assert!((n-nref).abs()<1e-3);
1056 assert!((d-dref).abs()<1e-3);
1057 }
1058
1059 #[test]
1060 fn test_aer2ned() {
1061 let az = deg2rad(33.0);
1062 let el = deg2rad(70.0);
1063 let slant_range = 1000.0;
1064
1065 let eref = 1.862775208165935e+02;
1066 let nref = 2.868422278517140e+02;
1067 let dref = -9.396926207859083e+02;
1068
1069 let (n, e, d)= aer2ned(az, el, slant_range);
1070
1071 assert!((e-eref).abs()<1e-3);
1072 assert!((n-nref).abs()<1e-3);
1073 assert!((d-dref).abs()<1e-3);
1074 }
1075
1076 #[test]
1077 fn test_ned2aer() {
1078 let az_ref = deg2rad(33.0);
1079 let el_ref = deg2rad(70.0);
1080 let range_ref = 1000.0;
1081
1082 let e = 1.862775208165935e+02;
1083 let n = 2.868422278517140e+02;
1084 let d = -9.396926207859083e+02;
1085
1086 let (az, el, range) = ned2aer(n, e, d);
1087
1088 assert!((az-az_ref).abs()<1e-6);
1089 assert!((el-el_ref).abs()<1e-6);
1090 assert!((range-range_ref).abs()<1e-3);
1091 }
1092
1093 #[test]
1094 fn test_ned2ecef() {
1095 let lat0 = deg2rad(42.0);
1096 let lon0 = deg2rad(-82.0);
1097 let alt0 = 200.0;
1098 let e = 1.862775210000000e+02;
1099 let n = 2.868422200000000e+02;
1100 let d = -9.396926200000000e+02;
1101
1102 let xref = 6.609301927610815e+05;
1103 let yref = -4.701424222957011e+06;
1104 let zref = 4.246579604632881e+06;
1105
1106 let (x,y,z) = ned2ecef(n, e, d, lat0, lon0, alt0, Ellipsoid::default());
1107
1108 assert!((x-xref).abs()<1e-3);
1109 assert!((y-yref).abs()<1e-3);
1110 assert!((z-zref).abs()<1e-3);
1111 }
1112
1113 #[test]
1114 fn test_ellipsoid_references() {
1115 let (a, b, f, e) = Ellipsoid::WGS84.parameters();
1116 assert!((a-6378137.0).abs() < 1E-6);
1117 assert!((b-6356752.314245).abs() < 1E-6);
1118 assert!((1.0/f-298.257223563).abs() < 1E-6);
1119 assert!((e-6.6943799E-3_f64).abs() < 1E-6);
1120 let (a, b, f, e) = Ellipsoid::WGS72.parameters();
1121 assert!((b-a*(1.0-f)).abs() < 1E-6);
1122 assert!((e-(f*(2.0-f))) < 1E-6);
1123 let (a, b, f, e) = Ellipsoid::WGS66.parameters();
1124 assert!((b-a*(1.0-f)).abs() < 1E-6);
1125 assert!((e-(f*(2.0-f))) < 1E-6);
1126 let (a, b, f, e) = Ellipsoid::WGS60.parameters();
1127 assert!((b-a*(1.0-f)).abs() < 1E-6);
1128 assert!((e-(f*(2.0-f))) < 1E-6);
1129 let (a, b, f, e) = Ellipsoid::PZ90.parameters();
1130 assert!((a-6378136.0).abs() < 1E-6);
1131 assert!((b-a*(1.0-f)).abs() < 1E-6);
1132 assert!((1.0/f-298.257839303).abs() < 1E-6);
1133 assert!((e-(f*(2.0-f))) < 1E-6);
1134 let (a, b, f, e) = Ellipsoid::GRS80.parameters();
1135 assert!((a-6378137.0).abs() < 1E-6);
1136 assert!((b-a*(1.0-f)).abs() < 1E-6);
1137 assert!((1.0/f-298.257222101).abs() < 1E-6);
1138 assert!((e-(f*(2.0-f))) < 1E-6);
1139 let (a, b, f, e) = Ellipsoid::BDC.parameters();
1140 assert!((a-6378137.0).abs() < 1E-6);
1141 assert!((b-a*(1.0-f)).abs() < 1E-6);
1142 assert!((1.0/f-298.257222101).abs() < 1E-6);
1143 assert!((e-(f*(2.0-f))) < 1E-6);
1144 let (a, b, f, e) = Ellipsoid::Bessel.parameters();
1145 assert!((b-a*(1.0-f)).abs() < 1E-6);
1146 assert!((e-(f*(2.0-f))) < 1E-6);
1147 let (a, b, f, e) = Ellipsoid::International.parameters();
1148 assert!((b-a*(1.0-f)).abs() < 1E-6);
1149 assert!((e-(f*(2.0-f))) < 1E-6);
1150 let (a, b, f, e) = Ellipsoid::Airy.parameters();
1151 assert!((b-a*(1.0-f)).abs() < 1E-6);
1152 assert!((e-(f*(2.0-f))) < 1E-6);
1153 }
1154
1155 #[test]
1156 fn test_ecef2ned() {
1157 let lat0 = deg2rad(42.0);
1158 let lon0 = deg2rad(-82.0);
1159 let alt0 = 200.0;
1160 let eref = 1.862775210000000e+02;
1161 let nref = 2.868422200000000e+02;
1162 let dref = -9.396926200000000e+02;
1163
1164 let (x,y,z) = ned2ecef(nref, eref, dref, lat0, lon0, alt0, Ellipsoid::default());
1165 let (n,e,d)= ecef2ned(x, y, z, lat0, lon0, alt0, Ellipsoid::default());
1166
1167 assert!((e-eref).abs()<1e-3);
1168 assert!((n-nref).abs()<1e-3);
1169 assert!((d-dref).abs()<1e-3);
1170 }
1171
1172 #[test]
1173 fn test_distance_calculation() {
1174 let new_york = (40.730610,-73.935242);
1175 let paris = (48.856614, 2.3522219);
1176 let buenos_aires = (-34.603722, -58.381592);
1177 let sydney = (-33.867487, 151.20699);
1178 let expected_km = 5831.0_f64;
1180 let d_km = distance(new_york, paris) / 1000.0_f64;
1181 assert!((expected_km - d_km).abs() < 1.0);
1182 let expected_km = 8527.0_f64;
1184 let d_km = distance(new_york, buenos_aires) / 1000.0_f64;
1185 assert!((expected_km - d_km).abs() < 1.0);
1186 let expected_km = 15990.0_f64;
1188 let d_km = distance(new_york, sydney) / 1000.0_f64;
1189 assert!((expected_km - d_km).abs() < 10.0);
1190 let expected_km = 11050.0_f64;
1192 let d_km = distance(buenos_aires, paris) / 1000.0_f64;
1193 assert!((expected_km - d_km).abs() < 10.0);
1194 }
1195}