提问者:小点点

获取在 180 度与 180 度经线相交的两个点之间的点


我在MapboxGL(js)世界地图上绘制了一条线,它遵循轨道物体的路径。我通过在对象轨道更新时将一组新的十进制经度/纬度坐标添加到线几何阵列中来实现这一点。

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

instead of:  we get:
     /             /
    /             /___
.../.....    ......... 180° meridian 
  /          ___
 /             /
/             /

这里和Mapbox的“公认”答案建议转换到0 /360经度范围,但这只是将问题从赤道转移到了极点。这对于大多数一般的建议来说是没问题的,但是对于轨道跟踪来说仍然是一个问题,因为我们可能会穿过0 /360子午线。

我的解决方案是使用多线几何,当我穿过这条子午线时,将我的坐标分解成新的数组,然而,这将总是留下一个微小的间隙,或者,如果我“180,lat”任一侧,我们会在子午线处得到一个“纽结”:

gap:        or kink:
     /            /
    /            /
........    .....|...  180° meridian 
                /
 /             /
/             /

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

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

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

我知道这是基本的Trig,但我的老人大脑让我失望了..再。。。。


共2个答案

匿名用户

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

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

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

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

匿名用户

解决!使用基本的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

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

 +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开始下一行,间隙完全闭合!

高中数学(嗯,毕达哥拉斯的天才)来拯救!我知道那老人的脑子里有个地方。。。。。