如何将地图上的两点线投影成曲线 OpenLayers

How to project two point line on the map into a curved line OpenLayers

据我所知,OpenLayers 中没有内置功能可以将两点的直线按照地球的曲率投影成曲线。

当我得到一条直通马达加斯加的路线时,这是一个问题:

这个问题的前端是否有任何解决方案,我在 OpenLayers 中遗漏的任何功能,或者是否有任何第三方解决方案来计算这个。

我知道这种计算在前端很难,而且还取决于两点之间的点的分辨率。

我不相信openlayers有针对这个问题的打包解决方案。然而,有一些方法可以解决这个问题,一种是使用 javascript 来获取两个点和 return 代表大圆路径的 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

但是,由于大多数渲染器不使用球面几何(而是将经纬度视为笛卡尔坐标系,这解释了您要避免的直线),这种建议的方法仍然会导致长线段接近北极,因为每段仍然是一条直线,并且极点本身占据了通常默认投影中的整条 top/bottom 线。一种解决方案是使用 arc.js 沿线采样更多点,请参阅此 gist (better view here,它会节省您的平移)。尽管如果长线段仍然存在,则可以通过裁剪地图的北部边缘或限制其可见性来解决此问题。

另一种方法是使用像 d3 这样的库,它可以与 openlayers 配对,并且默认使用球面几何 ( 因此这是我所知道的唯一库、工具或程序这将使多边形的缠绕顺序很重要(当使用地理坐标 space 时,因为它不会将地理坐标视为平面坐标 - 而技术上 geojsonlint 和其他 geojson 验证器会抱怨如果它被缠绕 "wrong",这些验证者没有考虑到您可能会选择多边形边缘另一侧的 space))。这是一个较低级别的库,但会以开箱即用的解决方案为代价提供更多自定义地图的能力。

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

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>