fix: 修正 Cesium 巡航车道中心对齐

This commit is contained in:
2026-08-08 15:21:49 +08:00
parent aeb2cec021
commit 5658e7337d
17 changed files with 1081 additions and 192 deletions

View File

@@ -149,23 +149,55 @@ def parse_height(feature_tags, default):
class Projector:
"""Equirectangular projection about the centre of the OSM bounds.
"""WGS84 ECEF to local ENU projection about the OSM bounds centre.
Output is metres in a local ENU frame (X east, Y north), which is what both
the Blender scene and the Cesium GLB are authored in.
the Blender scene and the Cesium GLB are authored in. Cesium places the
GLB with eastNorthUpToFixedFrame, so using the same ellipsoid transform is
required to keep route coordinates aligned across the whole scene.
"""
WGS84_A = 6378137.0
WGS84_E2 = 6.6943799901413165e-3
def __init__(self, bounds):
self.bounds = bounds
self.lon0 = (bounds["min_lon"] + bounds["max_lon"]) / 2
self.lat0 = (bounds["min_lat"] + bounds["max_lat"]) / 2
self.m_per_lat = 111320.0
self.m_per_lon = 111320.0 * math.cos(math.radians(self.lat0))
self._lon0_rad = math.radians(self.lon0)
self._lat0_rad = math.radians(self.lat0)
self._sin_lon0 = math.sin(self._lon0_rad)
self._cos_lon0 = math.cos(self._lon0_rad)
self._sin_lat0 = math.sin(self._lat0_rad)
self._cos_lat0 = math.cos(self._lat0_rad)
self._origin_ecef = self._ecef(self._lon0_rad, self._lat0_rad)
denominator = math.sqrt(1.0 - self.WGS84_E2 * self._sin_lat0 ** 2)
prime_vertical_radius = self.WGS84_A / denominator
meridional_radius = self.WGS84_A * (1.0 - self.WGS84_E2) / denominator ** 3
radians_per_degree = math.pi / 180.0
self.m_per_lon = prime_vertical_radius * self._cos_lat0 * radians_per_degree
self.m_per_lat = meridional_radius * radians_per_degree
def xy(self, lon_lat):
lon, lat = lon_lat
return ((lon - self.lon0) * self.m_per_lon,
(lat - self.lat0) * self.m_per_lat)
x, y, z = self._ecef(math.radians(lon), math.radians(lat))
dx = x - self._origin_ecef[0]
dy = y - self._origin_ecef[1]
dz = z - self._origin_ecef[2]
east = -self._sin_lon0 * dx + self._cos_lon0 * dy
north = (-self._sin_lat0 * self._cos_lon0 * dx
- self._sin_lat0 * self._sin_lon0 * dy
+ self._cos_lat0 * dz)
return east, north
def _ecef(self, lon_rad, lat_rad):
sin_lat = math.sin(lat_rad)
cos_lat = math.cos(lat_rad)
radius = self.WGS84_A / math.sqrt(1.0 - self.WGS84_E2 * sin_lat ** 2)
return (radius * cos_lat * math.cos(lon_rad),
radius * cos_lat * math.sin(lon_rad),
radius * (1.0 - self.WGS84_E2) * sin_lat)
def inside(self, lon_lat, pad=0.00035):
lon, lat = lon_lat