如何将地图上的两点线投影为曲线(OpenLayers)

3
就我所知,OpenLayers没有内置功能可以将两个点的直线投影为沿着地球曲率的曲线。
当我得到一条直线穿过马达加斯加的路线时,这就成了一个问题:

enter image description here

这个问题在前端上是否有解决方案?我是否错过了OpenLayers中的某些功能,或者是否有第三方解决方案可以计算这个问题。

我知道在前端上进行这种计算很困难,它还取决于两个点之间的点的分辨率。

1个回答

4
我不认为OpenLayers有针对这个问题的打包解决方案。然而,有一些处理此问题的选项,其中一个是使用JavaScript获取两个点并返回表示大圆路径的geoJson路线。
使用诸如arc.js之类的库,我们可以绘制两点之间的大圆弧线。
var generator = new arc.GreatCircle({x: -90, y: -70},{x: 89, y: 70}); // points to connect
var n = 50; // n of points
var coords = generator.Arc(n).geometries[0].coords;
var geojson = {"type":"Feature","geometry":{"type":"LineString","coordinates": coords},"properties":null } ;

然后,您可以将geojson传递给openlayers。请参见this gist。但是,由于大多数渲染器不使用球面几何(而是将纬度和经度视为笛卡尔坐标系,这解释了您试图避免的直线),因此这种建议的方法仍可能导致长线段接近北极,因为每个线段仍然是一条直线,并且极点本身占据了通常是默认投影中的整个顶部/底部线。一种解决方案是使用arc.js沿着线采样更多点,请参见此gist(更好的查看here,它将为您节省向上滚动的时间)。虽然如果长线段仍然存在,则可以通过裁剪地图的北部边缘或限制其可见性来修复它们。
使用类似d3这样的库,可以与openlayers配对使用,并默认使用球面几何 (因此是我所知道的唯一一个会关注多边形顺序的库、工具或程序(当使用地理坐标空间时),因为它不会将地理坐标视为平面 - 尽管从技术上讲,geojsonlint和其他geojson验证器会在多边形“错误”时发出警告,但这些验证器并没有考虑到您可能正在选择多边形边缘另一侧的空间)。这是一个较低级别的库,但会以牺牲开箱即用的解决方案为代价提供更多自定义地图的能力。

连接两个点的基本线条可能如下所示(取决于设置):

var geojson = {"type":"Feature","geometry":{"type":"LineString","coordinates": [[90,50],[-89,50]]},"properties":null };
var feature = svg.append("path")
  .datum(geojson)
  .attr("d",path);

var width = 600, height = 300;

var svg = d3.select("svg")
  .attr("width",width)
  .attr("height",height);
  
var projection = d3.geoMercator() // projection type
  .translate([width/2,height/2])
  .scale(width/Math.PI/2*0.7)
var path = d3.geoPath().projection(projection) // path generator

var geojson = [
{"type":"Feature","geometry":{"type":"LineString","coordinates": [[90,50],[-89,50]]},"properties":null },
{"type":"Feature","geometry":{"type":"LineString","coordinates": [[90,-50],[-89,50]]},"properties":null }];

var feature = svg.selectAll("path")
      .data(geojson)
      .enter().append("path")
      .attr("d",path)
      .attr("stroke","steelblue")
      .attr("stroke-width",3)
      
// Add the world to reference the lines:
d3.json("https://unpkg.com/world-atlas@1/world/110m.json", function(error, world) {
  if (error) throw error;

  svg.append("path")
    .datum(topojson.mesh(world))
    .attr("d",path)
    .attr("stroke","#ccc")
    .lower();
});
path {
  fill: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.js"></script>
<svg></svg>


嘿,谢谢你详细的回答。这个方法非常好用。 我使用了arc.js的例子,效果很棒。 干杯! - Mario Petrovic
我假设这个计算对浏览器的处理来说并不昂贵。我们在这里讨论的是应用程序生命周期中处理大量路由的情况。 - Mario Petrovic
根据过去的经验,这应该不会对浏览器性能造成太大影响,尽管我还没有对大圆弧和普通线进行任何性能测试。有三个成本:将线分割成许多沿着大圆弧的线段,然后投影和渲染这些线元素。一个潜在的优化是计算两个端点之间的大圆弧距离,并相应地调整采样点的数量(尽管由于在墨卡托投影中赤道附近的距离被压缩,这可能需要一些额外的考虑)。 - Andrew Reid
是的,我也有同样的想法。为了增加或减少距离的点数,甚至适用于较小或较大的屏幕。至于渲染方面,地图应该处理最终的缩放和修剪不可见的线条。再次感谢您的答案和见解 :) - Mario Petrovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接