{"id":13782343,"url":"https://github.com/ofmooseandmen/jord-rs","last_synced_at":"2025-04-22T23:14:39.182Z","repository":{"id":56553508,"uuid":"299372031","full_name":"ofmooseandmen/jord-rs","owner":"ofmooseandmen","description":"Geographical Position Calculations","archived":false,"fork":false,"pushed_at":"2024-10-05T03:59:15.000Z","size":379,"stargazers_count":10,"open_issues_count":1,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-22T23:14:31.752Z","etag":null,"topics":["geodesy","geodetics","geography","geospatial","kinematics","n-vector","rust","spherical-geometry"],"latest_commit_sha":null,"homepage":"https://docs.rs/jord/latest/jord","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ofmooseandmen.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-28T16:44:55.000Z","updated_at":"2025-02-10T10:23:24.000Z","dependencies_parsed_at":"2023-01-22T07:00:23.149Z","dependency_job_id":"e9064ed6-82da-4008-96c8-a8b10ccacde2","html_url":"https://github.com/ofmooseandmen/jord-rs","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofmooseandmen%2Fjord-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofmooseandmen%2Fjord-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofmooseandmen%2Fjord-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofmooseandmen%2Fjord-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ofmooseandmen","download_url":"https://codeload.github.com/ofmooseandmen/jord-rs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250337950,"owners_count":21414104,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["geodesy","geodetics","geography","geospatial","kinematics","n-vector","rust","spherical-geometry"],"created_at":"2024-08-03T18:01:35.493Z","updated_at":"2025-04-22T23:14:39.166Z","avatar_url":"https://github.com/ofmooseandmen.png","language":"Rust","funding_links":[],"categories":["Rust","Watchlist"],"sub_categories":[],"readme":"# Jord - Geographical Position Calculations\n\n[![crates.io](https://img.shields.io/crates/v/jord.svg?color=brightgreen)](https://crates.io/crates/jord)\n[![build](https://github.com/ofmooseandmen/jord-rs/workflows/CI/badge.svg)](https://github.com/ofmooseandmen/jord-rs/actions)\n[![coverage](https://codecov.io/gh/ofmooseandmen/jord-rs/graph/badge.svg?token=MEKNYZRK3V)](https://codecov.io/gh/ofmooseandmen/jord-rs)\n[![license](https://img.shields.io/badge/license-MIT-lightgray.svg)](https://opensource.org/license/mit)\n\n\u003e __Jord__ (_Swedish_) is __Earth__ (_English_)\n\nThe `jord` crate implements various geographical position calculations, featuring:\n\n- Conversions between ECEF (earth-centred, earth-fixed), latitude/longitude and [n-vector](http://www.navlab.net/Publications/A_Nonsingular_Horizontal_Position_Representation.pdf) positions for [spherical](crate::spherical::Sphere) and [ellipsoidal](crate::ellipsoidal::Ellipsoid) models,\n- [Local frame](crate::LocalFrame)s - body; local level, wander azimuth; north, east, down; east, north, up: delta between positions, target position from reference position and delta,\n- [Great circle](https://en.wikipedia.org/wiki/Great_circle) ([spherical](crate::spherical::Sphere)) navigation: surface distance, initial \u0026 final bearing, interpolated position, [minor arc](crate::spherical::MinorArc) intersection, cross track distance, angle turned, side of position...,\n- Kinematics ([spherical](crate::spherical::Sphere)): closest point of approach between tracks, minimum speed for intercept and time to intercept,\n- [Spherical Loop](crate::spherical::Loop)s ('simple polygons'): convex/concave, clockwise/anti-clockwise, contains position, [minimum bounding rectangle](crate::spherical::Rectangle), triangulation, spherical excess...,\n- [Spherical Cap](crate::spherical::Cap)s and [Rectangular Region](crate::spherical::Rectangle)s\n- Location-dependent radii of [ellispoid](crate::ellipsoidal::Ellipsoid)s.\n\n## Literature\n\nThe following references provide the theoretical basis of most of the algorithms:\n\n- [Non-singular Horizontal Position Representation; Gade, K.; 2010](https://www.navlab.net/Publications/A_Nonsingular_Horizontal_Position_Representation.pdf)\n- [Some Tactical Algorithms for Spherical Geometry](https://calhoun.nps.edu/bitstream/handle/10945/29516/sometacticalalgo00shud.pdf)\n- [Triangulation by Ear Clipping](https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf)\n\n## Solutions to the 10 examples from [NavLab](https://www.navlab.net/nvector)\n\n### Example 1: A and B to delta\nGiven two positions A and B. Find the exact vector from A to B in meters north, east and down, and find the direction (azimuth/bearing) to B, relative to north. Use WGS-84 ellipsoid.\n\n```\nuse jord::{Angle, Cartesian3DVector, GeodeticPosition, Length, LocalFrame, NVector};\nuse jord::ellipsoidal::Ellipsoid;\n\nlet a = GeodeticPosition::new(\n    NVector::from_lat_long_degrees(1.0, 2.0),\n    Length::from_metres(3.0)\n);\n\nlet b = GeodeticPosition::new(\n    NVector::from_lat_long_degrees(4.0, 5.0),\n    Length::from_metres(6.0)\n);\n\nlet ned = LocalFrame::ned(a, Ellipsoid::WGS84);\nlet delta = ned.geodetic_to_local_position(b);\n\nassert_eq!(Length::from_metres(331730.863), delta.x().round_mm()); // north\nassert_eq!(Length::from_metres(332998.501), delta.y().round_mm()); // east\nassert_eq!(Length::from_metres(17398.304), delta.z().round_mm()); // down\nassert_eq!(Length::from_metres(470357.384), delta.slant_range().round_mm());\nassert_eq!(Angle::from_degrees(45.10926), delta.azimuth().round_d5());\nassert_eq!(Angle::from_degrees(-2.11983), delta.elevation().round_d5());\n```\n\n### Example 2: B and delta to C\nGiven the position of vehicle B and a bearing and distance to an object C. Find the exact position of C. Use WGS-72 ellipsoid.\n\n```\nuse jord::{\n    Angle, Cartesian3DVector, GeodeticPosition, LatLong, Length, LocalFrame, LocalPosition,\n    NVector, Vec3,\n};\nuse jord::ellipsoidal::Ellipsoid;\n\nlet b = GeodeticPosition::new(\n    NVector::new(Vec3::new_unit(1.0, 2.0, 3.0)),\n    Length::from_metres(400.0)\n);\n\nlet yaw = Angle::from_degrees(10.0);\nlet pitch = Angle::from_degrees(20.0);\nlet roll = Angle::from_degrees(30.0);\nlet body = LocalFrame::body(yaw, pitch, roll, b, Ellipsoid::WGS72);\nlet delta = LocalPosition::from_metres(3000.0, 2000.0, 100.0);\n\nlet c = body.local_to_geodetic_position(delta);\nlet c_ll = LatLong::from_nvector(c.horizontal_position());\n\nassert_eq!(Angle::from_degrees(53.32638), c_ll.latitude().round_d5());\nassert_eq!(Angle::from_degrees(63.46812), c_ll.longitude().round_d5());\nassert_eq!(Length::from_metres(406.007), c.height().round_mm());\n```\n\n### Example 3: ECEF-vector to geodetic latitude\nGiven an ECEF-vector of a position. Find geodetic latitude, longitude and height (using WGS-84 ellipsoid).\n\n```\nuse jord::{Angle, GeocentricPosition, LatLong, Length, Surface};\nuse jord::ellipsoidal::Ellipsoid;\n\nlet c = GeocentricPosition::from_metres(0.9*6371e3, -1.0*6371e3, 1.1*6371e3);\nlet p = Ellipsoid::WGS84.geocentric_to_geodetic_position(c);\n\nlet p_ll = LatLong::from_nvector(p.horizontal_position());\nassert_eq!(Angle::from_degrees(39.37875), p_ll.latitude().round_d5());\nassert_eq!(Angle::from_degrees(-48.01279), p_ll.longitude().round_d5());\nassert_eq!(Length::from_metres(4702059.834), p.height().round_mm());\n```\n\n### Example 4: Geodetic latitude to ECEF-vector\nGiven geodetic latitude, longitude and height. Find the ECEF-vector (using WGS-84 ellipsoid).\n\n```\nuse jord::{Cartesian3DVector, GeocentricPosition, GeodeticPosition, Length, NVector, Surface};\nuse jord::ellipsoidal::Ellipsoid;\n\nlet p = GeodeticPosition::new(\n    NVector::from_lat_long_degrees(1.0, 2.0),\n    Length::from_metres(3.0)\n);\n\nlet c = Ellipsoid::WGS84.geodetic_to_geocentric_position(p);\n\nassert_eq!(\n    GeocentricPosition::from_metres(6_373_290.277, 222_560.201, 110_568.827),\n    c.round_mm(),\n);\n```\n\n**The following examples assume a spherical Earth model**\n\n### Example 5: Surface distance\nGiven position A and B. Find the surface distance (i.e. great circle distance).\n\n```\nuse jord::{Length, NVector};\nuse jord::spherical::Sphere;\n\nlet a = NVector::from_lat_long_degrees(88.0, 0.0);\nlet b = NVector::from_lat_long_degrees(89.0, -170.0);\n\nassert_eq!(\n    Length::from_kilometres(332.456),\n    Sphere::EARTH.distance(a, b).round_m()\n);\n```\n\n### Example 6: Interpolated position\nGiven the position of B at time t0 and t1. Find an interpolated position at time ti.\n\n```\nuse jord::{LatLong, NVector};\nuse jord::spherical::Sphere;\n\nlet a = NVector::from_lat_long_degrees(89.9, -150.0);\nlet b = NVector::from_lat_long_degrees(89.9, 150.0);\n\nlet t0 = 10.0;\nlet t1 = 20.0;\nlet ti = 16.0;\n\nlet f = (ti - t0) / (t1 - t0);\nlet pi = Sphere::interpolated_position(a, b, f);\n\nassert!(pi.is_some());\nassert_eq!(\n    LatLong::from_degrees(89.91282, 173.41323),\n    LatLong::from_nvector(pi.unwrap()).round_d5()\n);\n```\n\n### Example 7: Mean position/center\nGiven three positions A, B, and C. Find the mean position (center/midpoint).\n\n```\nuse jord::{LatLong, NVector};\nuse jord::spherical::Sphere;\n\nlet ps = vec![\n    NVector::from_lat_long_degrees(90.0, 0.0),\n    NVector::from_lat_long_degrees(60.0, 10.0),\n    NVector::from_lat_long_degrees(50.0, -20.0)\n];\n\nlet m = Sphere::mean_position(\u0026ps);\n\nassert!(m.is_some());\nassert_eq!(\n    LatLong::from_degrees(67.23615, -6.91751),\n    LatLong::from_nvector(m.unwrap()).round_d5()\n);\n```\n\n### Example 8: A and azimuth/distance to B\nGiven position A and an azimuth/bearing and a (great circle) distance. Find the destination point B.\n\n```\nuse jord::{Angle, LatLong, Length, NVector};\nuse jord::spherical::Sphere;\n\nlet p =  NVector::from_lat_long_degrees(80.0, -90.0);\nlet azimuth = Angle::from_degrees(200.0);\nlet distance = Length::from_metres(1000.0);\n\nlet d = Sphere::EARTH.destination_position(p, azimuth, distance);\n\nassert_eq!(\n    LatLong::from_degrees(79.99155, -90.01770),\n    LatLong::from_nvector(d).round_d5()\n);\n```\n\n### Example 9: Intersection of two paths / triangulation\nGiven path A going through A1 and A2, and path B going through B1 and B2. Find the intersection of the two paths.\n\n```\nuse jord::{LatLong, NVector};\nuse jord::spherical::MinorArc;\n\nlet a = MinorArc::new(\n    NVector::from_lat_long_degrees(50.0, 180.0),\n    NVector::from_lat_long_degrees(90.0, 180.0)\n);\n\nlet b = MinorArc::new(\n    NVector::from_lat_long_degrees(60.0, 160.0),\n    NVector::from_lat_long_degrees(80.0, -140.0)\n);\n\nlet i = a.intersection(b);\n\nassert!(i.is_some());\nassert_eq!(\n    LatLong::from_degrees(74.16345, 180.0),\n    LatLong::from_nvector(i.unwrap()).round_d5()\n);\n```\n\n### Example 10: Cross track distance (cross track error)\nGiven path A going through A1 and A2, and a point B. Find the cross track distance/cross track error between B and the path.\n\n```\nuse jord::{LatLong, Length, NVector};\nuse jord::spherical::{GreatCircle, Sphere};\n\nlet a = GreatCircle::new(\n    NVector::from_lat_long_degrees(0.0, 0.0),\n    NVector::from_lat_long_degrees(10.0, 0.0)\n);\n\nlet b =  NVector::from_lat_long_degrees(1.0, 0.1);\n\nlet d = Sphere::EARTH.cross_track_distance(b, a);\n\nassert_eq!(Length::from_metres(11117.8), d.round_dm());\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofmooseandmen%2Fjord-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fofmooseandmen%2Fjord-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofmooseandmen%2Fjord-rs/lists"}