如何将地图上的两点线投影成曲线 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>
据我所知,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>