Files
rerun-io--rerun/examples/python/nuscenes_dataset/nuscenes_dataset/export_gps.py
T
2026-07-13 13:05:14 +08:00

88 lines
3.2 KiB
Python

# from nuScenes dev-kit: https://github.com/nutonomy/nuscenes-devkit/blob/4df2701feb3436ae49edaf70128488865a3f6ff9/python-sdk/nuscenes/scripts/export_poses.py
# Code contributed by jean-lucas, 2020.
"""Exports the nuScenes ego poses as "GPS" coordinates (lat/lon) for each scene into JSON or KML formatted files."""
from __future__ import annotations
import math
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Sequence
EARTH_RADIUS_METERS = 6.378137e6
REFERENCE_COORDINATES = {
"boston-seaport": [42.336849169438615, -71.05785369873047],
"singapore-onenorth": [1.2882100868743724, 103.78475189208984],
"singapore-hollandvillage": [1.2993652317780957, 103.78217697143555],
"singapore-queenstown": [1.2782562240223188, 103.76741409301758],
}
def get_coordinate(ref_lat: float, ref_lon: float, bearing: float, dist: float) -> tuple[float, float]:
"""
Using a reference coordinate, extract the coordinates of another point in space given its distance and bearing
to the reference coordinate. For reference, please see: https://web.archive.org/web/2025/https://www.movable-type.co.uk/scripts/latlong.html.
Parameters
----------
ref_lat : float
Latitude of the reference coordinate in degrees, e.g., 42.3368.
ref_lon : float
Longitude of the reference coordinate in degrees, e.g., 71.0578.
bearing : float
The clockwise angle in radians between the target point, reference point, and the axis pointing north.
dist : float
The distance in meters from the reference point to the target point.
Returns
-------
tuple[float, float]
A tuple of latitude and longitude.
"""
lat, lon = math.radians(ref_lat), math.radians(ref_lon)
angular_distance = dist / EARTH_RADIUS_METERS
target_lat = math.asin(
math.sin(lat) * math.cos(angular_distance) + math.cos(lat) * math.sin(angular_distance) * math.cos(bearing),
)
target_lon = lon + math.atan2(
math.sin(bearing) * math.sin(angular_distance) * math.cos(lat),
math.cos(angular_distance) - math.sin(lat) * math.sin(target_lat),
)
return math.degrees(target_lat), math.degrees(target_lon)
def derive_latlon(location: str, pose: dict[str, Sequence[float]]) -> tuple[float, float]:
"""
Extract lat/lon coordinate from pose.
This makes the following two assumptions in order to work:
1. The reference coordinate for each map is in the south-western corner.
2. The origin of the global poses is also in the south-western corner (and identical to 1).
Parameters
----------
location : str
The name of the map the poses correspond to, i.e., `boston-seaport`.
pose : dict[str, Sequence[float]]
nuScenes egopose.
Returns
-------
tuple[float, float]
Latitude and longitude coordinates in degrees.
"""
assert location in REFERENCE_COORDINATES, f"Error: The given location: {location}, has no available reference."
reference_lat, reference_lon = REFERENCE_COORDINATES[location]
x, y = pose["translation"][:2]
bearing = math.atan(x / y)
distance = math.sqrt(x**2 + y**2)
lat, lon = get_coordinate(reference_lat, reference_lon, bearing, distance)
return lat, lon