获取以 180 度穿过 180 度子午线的两点之间的点

Get point between two points crossing the 180 degree meridian at 180 degrees

我正在 MapboxGL (js) 世界地图上绘制一条沿着轨道物体路径的线。我通过在对象轨道更新时向线几何数组添加一组新的十进制 longitude/latitude 坐标来实现此目的。

Mapbox(和其他)有一个已知问题,当绘制一条穿过 180° 子午线(经度)的线时,我们没有得到一条从 a 到 b 的漂亮直线,我们得到一条很长的线从 a 到 b 环绕整个地球:

而不是:我们得到:
     / /
    //___
.../..... ......... 180° 子午线
  / ___
 / /
/ /

此处和 Mapbox 上的“已接受”答案建议转移到 0°/360° 经度范围,但这只会将问题从赤道转移到极点。这对于大多数一般建议来说很好,但对于我们可能穿过 0°/360° 子午线的轨道跟踪来说仍然是一个问题。

我的解决方案是使用 MultiLine 几何图形,并在我穿过这条子午线时将我的坐标分解成新的数组,但是,这总是会留下一个小间隙,或者,如果我在任一侧“180,纬度”,我们得到子午线上的“扭结”:

差距:或扭结:
     / /
    / /
.......... ......|... 180°子午线
                /
 / /
/ /

所以我需要弄清楚如果经度在子午线上,那么精确纬度是多少,知道两边的起点和终点:

 +170 | p2 /:
       | / :
       | / :
  180 -|-----/ 像素? -- 180°经线
       | /: :
 (液化天然气) | / : :
       | / : :
 -170 |_/___:___:___
        p1 x?
          (纬度)

我需要求解纬度 x 以便生成 pX(如果经度为 180,则知道 p1 和 p2)。一旦我有了 pX,我就可以将它添加到最后一行的末尾和下一行的开头,从而缩小差距(或平滑“扭结”)。

我知道这是基本的 Trig,但我的老脑子又让我失望了.. ....

已解决!使用基本 Trig(在写问题时 - 所以无论如何我都会发布它,以防它帮助其他人):

我们基本上是在玩两个直角三角形:p1 到 p2,以及较小的直角三角形,其对边停止在子午线处,它们都具有相同的斜边角。所以,我们有:

 +170  |     p2 /| 
       |       / | 
       |      /  | 
  180 -|-----/ pX? --  180° meridian 
       |    /:   | 
 (lng) |   / : A | 
       |  / B:   | 
 -170  |_/___:___|___
        p1   x?  
          (lat)    

其中A是我们p1到p2的直角三角形,B是从p1经度到子午线的三角形,我们需要计算其邻边。

毕达哥拉斯基本上告诉我们,我们所需要的只是直角三角形的两个数据点(除了直角)来解决任何其他问题。

我们已经有了A的相反和相邻的长度:

 +170  |     p2 /| 
       |       /α| 
       |      /  | 
  180 -|--   /   | --  180° meridian 
       |    /    | 
 (lng) |   /  A  | oppositeA
       |  /      | 
 -170  |_/β______|___
        p1  adjacentA     
          (lat)    

所以从这里我们需要计算A的斜边,得到A的斜边(α)的角度,以便后面使用:

// add 360 to a negative longitude to shift lng from -180/+180, to 0/360
p1 = { lng: p1.lng < 0 ? p1.lng + 360 : p1.lng, lat: p1.lat }
p2 = { lng: p2.lng < 0 ? p2.lng + 360 : p2.lng, lat: p2.lat }
let oppositeA = Math.abs(p2.lng - p1.lng) // get A opposite length
let adjacentA = Math.abs(p2.lat - p1.lat) // get A adjacent length
let hypotenuseA = Math.sqrt(Math.pow(oppositeA,2) + Math.pow(adjacentA,2)) // calc A hypotenuse
let angleA = Math.asin(oppositeA / hypotenuseA) // calc A hypotenuse angle

现在我们需要 new 与 B 的对角(p1.lng 到 180)和我们计算出的 A 的角度来计算出 B 的新斜边,这样我们就可以得到B:

的新 adjacent
 +170  |     p2 /  
       |       /   
       |      /    
  180 -|--   /     --  180° meridian 
       |    /: B    
 (lng) |   /α:     
       |  /  : oppositeB
 -170  |_/___:___ ___
        p1  adjacentB
          (lat)    
let oppositeB = Math.abs(180 - p1.lng) // get B opposite
let hypotenuseB = oppositeB / Math.cos(angleA) // calc B hypotenuse using A angle
let adjacentB = Math.sqrt(Math.pow(oppositeB,2) + Math.pow(hypotenuseB,2)); calc B adjacent

现在我们添加与 p1 相邻的新纬度,我们有 x!所以:

let pX = { lng: 180, lat: p1.lat + adjacentB }

结束最后一行数组,从pX开始下一行,差距完美闭合!

高中数学(嗯,毕达哥拉斯的天才)来拯救!我知道它在那个老人脑子里的某个地方嘎嘎作响.....

以这种方式分割线的简单方法是使用 Turf 的 lineSplit 函数。类似于:

const meridian = turf.lineString([[180, -90], [180, 90]]);
const linePieces = turf.lineSplit(myline, meridian);

我没试过这个,所以不确定Turf本身在子午线上是否有任何怪异。如果是这样,您可能需要暂时将坐标转换到其他地方或其他地方。

在任何情况下都比自己做三角函数要好,尤其是因为它可能会在世界不平坦的情况下引入错误。