【问题标题】:How to project two point line on the map into a curved line OpenLayers如何将地图上的两点线投影成曲线 OpenLayers
【发布时间】:2017-11-01 11:16:45
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: openlayers curve points map-projections


    【解决方案1】:

    我不相信 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 示例,它运行良好。干杯。
    • 我假设这个计算对于浏览器来说并不昂贵。我们在这里谈论的是在应用程序的生命周期中正在处理的许多路线
    • 根据过去的经验,它应该不会对浏览器性能造成太大的损害,尽管我还没有对大弧线和普通线进行任何性能测试。成本有 3 个:将线沿大弧线分割成许多线段,然后投影和渲染这些线元素。一种潜在的优化是计算两个端点之间的大弧距离并相应地调整采样点的数量(尽管距离在墨卡托赤道附近被压缩,这可能需要一些额外的考虑)。
    • 是的,我也是这么想的。为距离增加或减少等效的点数,甚至为更小或更大的屏幕。至于渲染,地图应该负责最终的缩放和修剪不可见的线条。再次感谢您的回答和这个网站:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多