CesiumJS:如何正确获取地球表面线段的中点?
问题:Cesium中计算纬线线段中点纬度不符合预期
问题背景
定义了两条沿纬线的线段,尝试计算中点时,纬度结果与预期不符:
- 第一条线段端点
[-150,45]和[150,45],预期中点纬度45,实际得到49.11979677835345 - 第二条线段端点
[150,40]和[-150,40],预期中点纬度40,实际得到44.111242494938004
初始代码
const testLines = [ [ [ -150, 45 ], [ 150, 45 ] ], // <--- [ [ 150, 40 ], [ -150, 40 ] ], // ---> ]; testLines.forEach( ( line ) => { const endpoints = Cesium.Cartesian3.fromDegreesArray( [ ...line[0], ...line[1] ] ); const e1e2 = new Cesium.Cartesian3(); const halfe1e2 = new Cesium.Cartesian3(); const midpoint = new Cesium.Cartesian3(); Cesium.Cartesian3.subtract( endpoints[1], endpoints[0], e1e2 ); Cesium.Cartesian3.multiplyByScalar( e1e2, 0.5, halfe1e2 ); Cesium.Cartesian3.add( endpoints[0], halfe1e2, midpoint ); const carto = Cesium.Cartographic.fromCartesian( midpoint ); const lon = Cesium.Math.toDegrees( carto.longitude ); const lat = Cesium.Math.toDegrees( carto.latitude ); console.log( `${lon}, ${lat}` ); })
输出结果
180, 49.11979677835345 180, 44.111242494938004
已尝试的方法
- 直接使用
Cesium.Cartesian3.midpoint和Cesium.Cartesian3.lerp(endpoints[0], endpoints[1], .5, midpoint),结果一致 - 使用
EllipsoidGeodesic插值计算,代码如下,结果仍然相同:
const a = new Cesium.Cartographic() const b = new Cesium.Cartographic() Cesium.Cartographic.fromDegrees( line[0][0], line[0][1], 0, a ); Cesium.Cartographic.fromDegrees( line[1][0], line[1][1], 0, b ); const globeCalc = new Cesium.EllipsoidGeodesic( a, b ) const midpoint = new Cesium.Cartographic() globeCalc.interpolateUsingFraction( .5, midpoint ) const lon = Cesium.Math.toDegrees( midpoint.longitude ); const lat = Cesium.Math.toDegrees( midpoint.latitude ); console.log( `${lon}, ${lat}` );
原因及解决方案
核心原因
你混淆了两个关键概念:
- 笛卡尔空间中点:
Cartesian3相关方法计算的是3D空间中两点的直线中点,该点不在椭球表面,投影回椭球后会出现纬度偏移。 - 测地线中点:
EllipsoidGeodesic计算的是椭球表面两点的最短路径(测地线)中点,而除赤道外的纬线并非测地线,测地线会更靠近极点,因此中点纬度会高于原纬线纬度。
解决方案(获取纬线中点)
如果需要的是沿等纬度线的中点,直接在经纬度层面计算即可,无需转换为笛卡尔坐标:
testLines.forEach( ( line ) => { const [lon1, lat1] = line[0]; const [lon2, lat2] = line[1]; // 处理跨180°经线的经度计算 let lonMid; if (Math.abs(lon2 - lon1) > 180) { const delta = (lon2 + 360 - lon1) / 2; lonMid = (lon1 + delta) % 360; lonMid = lonMid > 180 ? lonMid - 360 : lonMid; } else { lonMid = (lon1 + lon2) / 2; } // 纬度直接取平均值(沿纬线的中点纬度与端点一致) const latMid = (lat1 + lat2) / 2; console.log(`${lonMid}, ${latMid}`); })
说明
- 对于沿纬线的线段,其中点纬度必然与端点纬度相同,无需复杂计算。
- 如果确实需要测地线中点,那么之前的结果是正确的,这是椭球测地线的固有特性。
内容的提问来源于stack exchange,提问作者Eric G
相关产品推荐
相关产品推荐

