有没有办法让一个形状从一条边穿过日线边经线(180°经度)到Leaflet.js的地图的另一边?
我看过:
但我不确定我能做些什么才能让它可靠地划过日期线......
提前谢谢!
答案 0 :(得分:8)
哦,你正在点击antimeridian artifacts。你不是第一个,也不会是最后一个。
在Leaflet中,基本上有两种解决此问题的方法:
如果您了解GIS工具,请预处理多边形,这样您最终会得到两个(或可能更多)多边形。请参阅«How can I make a polyline wrap around the world?»。
一旦你有一个文件中有几个没有穿过反子弹的多边形,它们就会渲染得很好。如果对多边形应用边框,则会出现伪影(即,在反射影像处的垂直多边形边界,跨越多边形内部),因此您可能希望使用多边形边缘剪切多边形和折线。你想要很好地渲染。
如果您不想事先剪切多边形,可以让网络浏览器动态执行。
有一些实用程序可以在这里提供帮助,但我特别指出Leaflet.VectorGrid。通过利用geojson-vt,它可以将多边形及其边缘切割为平铺大小的多边形和多边形边。它可以handle geometries crossing the antimeridian quite well。
您可能希望直接查看geojson-vt,或者turf.js进行一些动态地理处理。
[-180..180]
范围 Leaflet可以处理[-180..180]
范围之外的经度。在Leaflet中,经度仅包含 TileLayer
的图块,而不包括标记或折线。
换句话说:[0, -179]
处的标记显示在与[0, 181]
不同的位置。请参阅this answer for an example。
换句话说:从[0, 179]
到[0, -179]
的一条线长358度,但从[0, 179]
到[0, 181]
的线条长度为2度。
换句话说:您可以使用坐标经过[-180..180]
范围以外的经度的线串或多边形,这对于Leaflet来说很好。对于很多GIS软件来说并不好(事实上,我认为新的GeoJSON规范禁止它)。但它会使Leaflet感到高兴。
答案 1 :(得分:1)
当您使用圆柱投影时,就像 Leaflet 所做的那样,它可以通过三角学相对容易地解决。我的解决方案是基于上面Ivan's answer的第一种方法,即在第180个子午线处将线切割成两部分。我的解决方案并不完美,我将在下面展示,但这是一个好的开始。
代码如下:
function addLineToMap(start, end) {
if (Math.abs(start[1] - end[1]) > 180.0) {
const start_dist_to_antimeridian = start[1] > 0 ? 180 - start[1] : 180 + start[1];
const end_dist_to_antimeridian = end[1] > 0 ? 180 - end[1] : 180 + end[1];
const lat_difference = Math.abs(start[0] - end[0]);
const alpha_angle = Math.atan(lat_difference / (start_dist_to_antimeridian + end_dist_to_antimeridian)) * (180 / Math.PI) * (start[1] > 0 ? 1 : -1);
const lat_diff_at_antimeridian = Math.tan(alpha_angle * Math.PI / 180) * start_dist_to_antimeridian;
const intersection_lat = start[0] + lat_diff_at_antimeridian;
const first_line_end = [intersection_lat, start[1] > 0 ? 180 : -180];
const second_line_start = [intersection_lat, end[1] > 0 ? 180 : -180];
L.polyline([start, first_line_end]).addTo(map);
L.polyline([second_line_start, end]).addTo(map);
} else {
L.polyline([start, end]).addTo(map);
}
}
这将计算线穿过第 180 条子午线的纬度,并在第 180 条子午线上从起点到该纬度绘制第一条线,然后从该点到终点绘制第二条线。
下图显示了一个结果示例。
尽管我相当确定我的计算经过数学验证,但在两条线分开的地方还是有一个小问题。我不确定这是由于 Leaflet 地图的渲染,还是我的计算中的实际错误。
起点是[35.552299, 139.779999]
,终点是[64.81510162, -147.8560028]
。
点之间的总纵向差为72.364
,纬度差为29.263
。使用下面的代码或 online calculator,角度 α
是 22.018
。仅取起点到第 180 条子午线的距离和角度 α
,起点与交点之间的 latitudinal difference 为 16.264
。加上起点的纬度和这个值,我们得到第 180 个子午线的纬度 51.8166。在地图上画一条直线告诉我这个值应该稍微高一点,但我不知道为什么或如何计算。
如果您想要一条能够准确显示地球曲线的曲线,我强烈建议您使用 Leaflet.Geodisic。它易于使用,并且内置了反子午线问题的解决方案,因此您不必担心。