#geospatial #geography #n-vector

jord

地理位置计算(椭圆体和球体模型)

13个重大版本发布

0.14.0 2024年1月29日
0.13.0 2023年12月6日
0.12.0 2023年12月3日
0.11.0 2023年11月28日

地理空间类别中排名34

Download history 88/week @ 2024-03-31 15/week @ 2024-05-19 1/week @ 2024-05-26

每月下载量176

MIT许可

330KB
6K SLoC

Jord - 地理位置计算

crates.io build coverage license

Jord (瑞典语)是 Earth (英语)

jord crate实现了各种地理位置计算,包括

  • ECEF(地球中心,地球固定)、纬度/经度和n-vector位置之间的转换,适用于球体和椭圆体模型,
  • 局部坐标系 - 物体;局部水平,游移方位;北、东、下;东、北、上:位置之间的差值,从参考位置到目标位置的差值和方向,
  • 大圆(球体)导航:表面距离,初始和最终方位,插值位置,小圆交点,交叉航迹距离,转弯角度,点的侧面等,
  • 运动学(球体):轨迹之间的最近点,拦截的最小速度和时间,
  • 球体环(简单的多边形):凸/凹,顺时针/逆时针,包含点,最小外接矩形,三角剖分,球面过剩等,
  • 球面帽矩形区域
  • 椭圆体的位置相关半径。

文献

以下参考文献提供了大多数算法的理论基础

解决NavLab的10个示例的解决方案

示例1:A和B到delta

给定两个位置A和B。找到从A到B的精确向量(北、东和下,米),并找到相对于北的方向(方位/航向)。使用WGS-84椭圆体。

use jord::{Angle, Cartesian3DVector, GeodeticPos, Length, LocalFrame, NVector};
use jord::ellipsoidal::Ellipsoid;

let a = GeodeticPos::new(
    NVector::from_lat_long_degrees(1.0, 2.0),
    Length::from_metres(3.0)
);

let b = GeodeticPos::new(
    NVector::from_lat_long_degrees(4.0, 5.0),
    Length::from_metres(6.0)
);

let ned = LocalFrame::ned(a, Ellipsoid::WGS84);
let delta = ned.geodetic_to_local_pos(b);

assert_eq!(Length::from_metres(331730.863), delta.x().round_mm()); // north
assert_eq!(Length::from_metres(332998.501), delta.y().round_mm()); // east
assert_eq!(Length::from_metres(17398.304), delta.z().round_mm()); // down
assert_eq!(Length::from_metres(470357.384), delta.slant_range().round_mm());
assert_eq!(Angle::from_degrees(45.10926), delta.azimuth().round_d5());
assert_eq!(Angle::from_degrees(-2.11983), delta.elevation().round_d5());

示例2:B和delta到C

给定车辆B的位置和指向对象C的方位和距离。找到C的确切位置。使用WGS-72椭圆体。

use jord::{
    Angle, Cartesian3DVector, GeodeticPos, LatLong, Length, LocalFrame, LocalPositionVector,
    NVector, Vec3,
};
use jord::ellipsoidal::Ellipsoid;

let b = GeodeticPos::new(
    NVector::new(Vec3::new_unit(1.0, 2.0, 3.0)),
    Length::from_metres(400.0)
);

let yaw = Angle::from_degrees(10.0);
let pitch = Angle::from_degrees(20.0);
let roll = Angle::from_degrees(30.0);
let body = LocalFrame::body(yaw, pitch, roll, b, Ellipsoid::WGS72);
let delta = LocalPositionVector::from_metres(3000.0, 2000.0, 100.0);

let c = body.local_to_geodetic_pos(delta);
let c_ll = LatLong::from_nvector(c.horizontal_position());

assert_eq!(Angle::from_degrees(53.32638), c_ll.latitude().round_d5());
assert_eq!(Angle::from_degrees(63.46812), c_ll.longitude().round_d5());
assert_eq!(Length::from_metres(406.007), c.height().round_mm());

示例3:ECEF向量到大地纬度

给定一个位置的ECEF向量。找到大地纬度、经度和高度(使用WGS-84椭圆体)。

use jord::{Angle, GeocentricPos, LatLong, Length, Surface};
use jord::ellipsoidal::Ellipsoid;

let c = GeocentricPos::from_metres(0.9*6371e3, -1.0*6371e3, 1.1*6371e3);
let p = Ellipsoid::WGS84.geocentric_to_geodetic(c);

let p_ll = LatLong::from_nvector(p.horizontal_position());
assert_eq!(Angle::from_degrees(39.37875), p_ll.latitude().round_d5());
assert_eq!(Angle::from_degrees(-48.01279), p_ll.longitude().round_d5());
assert_eq!(Length::from_metres(4702059.834), p.height().round_mm());

示例4:大地纬度到ECEF向量

给定大地纬度、经度和高度。找到ECEF向量(使用WGS-84椭圆体)。

use jord::{Cartesian3DVector, GeocentricPos, GeodeticPos, Length, NVector, Surface};
use jord::ellipsoidal::Ellipsoid;

let p = GeodeticPos::new(
    NVector::from_lat_long_degrees(1.0, 2.0),
    Length::from_metres(3.0)
);

let c = Ellipsoid::WGS84.geodetic_to_geocentric(p);

assert_eq!(
    GeocentricPos::from_metres(6_373_290.277, 222_560.201, 110_568.827),
    c.round_mm(),
);

以下示例假设球形地球模型

示例5:表面距离

给定位置 A 和 B。求表面积(即大圆距离)。

use jord::{Length, NVector};
use jord::spherical::Sphere;

let a = NVector::from_lat_long_degrees(88.0, 0.0);
let b = NVector::from_lat_long_degrees(89.0, -170.0);

assert_eq!(
    Length::from_kilometres(332.456),
    Sphere::EARTH.distance(a, b).round_m()
);

示例 6:插值位置

给定时间 t0 和 t1 的位置 B。求时间 ti 的插值位置。

use jord::{LatLong, NVector};
use jord::spherical::Sphere;

let a = NVector::from_lat_long_degrees(89.9, -150.0);
let b = NVector::from_lat_long_degrees(89.9, 150.0);

let t0 = 10.0;
let t1 = 20.0;
let ti = 16.0;

let f = (ti - t0) / (t1 - t0);
let pi = Sphere::interpolated_pos(a, b, f);

assert!(pi.is_some());
assert_eq!(
    LatLong::from_degrees(89.91282, 173.41323),
    LatLong::from_nvector(pi.unwrap()).round_d5()
);

示例 7:平均位置/中心

给定三个位置 A、B 和 C。求平均位置(中心/中点)。

use jord::{LatLong, NVector};
use jord::spherical::Sphere;

let ps = vec![
    NVector::from_lat_long_degrees(90.0, 0.0),
    NVector::from_lat_long_degrees(60.0, 10.0),
    NVector::from_lat_long_degrees(50.0, -20.0)
];

let m = Sphere::mean_position(&ps);

assert!(m.is_some());
assert_eq!(
    LatLong::from_degrees(67.23615, -6.91751),
    LatLong::from_nvector(m.unwrap()).round_d5()
);

示例 8:A 和 B 的方位角/距离

给定位置 A、一个方位角/航向和(大圆)距离。求目标点 B。

use jord::{Angle, LatLong, Length, NVector};
use jord::spherical::Sphere;

let p =  NVector::from_lat_long_degrees(80.0, -90.0);
let azimuth = Angle::from_degrees(200.0);
let distance = Length::from_metres(1000.0);

let d = Sphere::EARTH.destination_pos(p, azimuth, distance);

assert_eq!(
    LatLong::from_degrees(79.99155, -90.01770),
    LatLong::from_nvector(d).round_d5()
);

示例 9:两条路径的交点/三角测量法

给定通过 A1 和 A2 的路径 A 和通过 B1 和 B2 的路径 B。求两条路径的交点。

use jord::{LatLong, NVector};
use jord::spherical::MinorArc;

let a = MinorArc::new(
    NVector::from_lat_long_degrees(50.0, 180.0),
    NVector::from_lat_long_degrees(90.0, 180.0)
);

let b = MinorArc::new(
    NVector::from_lat_long_degrees(60.0, 160.0),
    NVector::from_lat_long_degrees(80.0, -140.0)
);

let i = a.intersection(b);

assert!(i.is_some());
assert_eq!(
    LatLong::from_degrees(74.16345, 180.0),
    LatLong::from_nvector(i.unwrap()).round_d5()
);

示例 10:交叉航迹距离(交叉航迹误差)

给定通过 A1 和 A2 的路径 A 和点 B。求 B 和路径之间的交叉航迹距离/交叉航迹误差。

use jord::{LatLong, Length, NVector};
use jord::spherical::{GreatCircle, Sphere};

let a = GreatCircle::new(
    NVector::from_lat_long_degrees(0.0, 0.0),
    NVector::from_lat_long_degrees(10.0, 0.0)
);

let b =  NVector::from_lat_long_degrees(1.0, 0.1);

let d = Sphere::EARTH.cross_track_distance(b, a);

assert_eq!(Length::from_metres(11117.8), d.round_dm());

无运行时依赖