【问题标题】:Get point between two points crossing the 180 degree meridian at 180 degrees获取以 180 度穿过 180 度子午线的两点之间的点
【发布时间】:2021-09-28 03:34:45
【问题描述】:

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

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,但我的老脑又让我失望了......再次......

【问题讨论】:

    标签: coordinates latitude-longitude mapbox-gl-js calculation


    【解决方案1】:

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

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

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

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

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

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

    +170 | p2 /| | /α| | / | 180 -|-- / | -- 180°子午线 | / | (液化天然气) | /一个|对面A | / | -170 |_/β______|___ p1邻接A (纬度)

    所以从这里我们需要计算 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 相对的 new(p1.lng 到 180)和我们计算的 A 的角度来计算 B 的新斜边,这样我们就可以得到新的 adjacent B:

    +170 | p2 / | / | / 180 -|-- / -- 180°子午线 | /:乙 (液化天然气) | /α: | / : 对面B -170 |_/___:___ ___ p1 相邻 B (纬度)
    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开始下一个,差距完美闭合!

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

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

      • 谢谢!我以前没见过 turf.js!我不愿意为单个计算加载整个库,但如果基本 Trig 在高缩放时给我带来不好的结果(假设 lineSplit 方法也不会在子午线引起怪异!),那可能是值得的。我意识到世界不是平坦的,或者确实不是一个完美的球体(我们的旋转使我们中间有点胖),这意味着我可能有点偏离,尤其是在赤道,但对于我正在使用的天平,“足够接近似乎足够好”..到目前为止......我会试一试并报告。
      • 我试了一下,不幸的是 lineSplit 和 lineIntersect 返回了空的特征数组。我认为这有点错误,因为即使剪切和粘贴他们的示例也返回空。作为记录,我的 Trig 尝试在赤道处产生了一个小扭结,但它只差了几米。在两极看起来很完美。这对我来说已经足够了,而且 Trig 的成本相对较低!
      • 更正:turf.lineIntersect 从 6.5.0 版开始工作,但也受到“世界不平坦”问题的诅咒。放大文档示例,您将看到位置错误。如果您查看源代码,它们使用的是笛卡尔坐标,而不是球面坐标。我使用原始 Trig 获得相同的“精度”:P 网上有一些可怕的数学示例可以校正球形,但足够接近对我来说已经足够了:D
      猜你喜欢
      • 1970-01-01
      • 2016-09-15
      • 1970-01-01
      • 1970-01-01
      • 2018-06-10
      • 1970-01-01
      • 2018-10-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多