Leaflet 地图上的多边形交点显示偏移

Leaflet 地图上的多边形交点显示偏移,leaflet,mapbox,turfjs,Leaflet,Mapbox,Turfjs,我试图找到地图上绘制的两个多边形之间的相交区域。 我使用了一种求两个多边形相交的方法 它适用于较小的区域,但对于较大区域的多边形,它开始在交点处显示一些偏移,偏移随着距离的增加而增加。 这也仅适用于具有斜线的多边形(垂直线和水平线的交点似乎工作良好) 我已经为此创建了一个JSFIDLE: 我试图找到黑色和蓝色多边形之间的交点,我得到的是红色多边形,它从应该的位置移动 var mapLayer = L.map('mapid', { zoomAnimation: false }); var pid

我试图找到地图上绘制的两个多边形之间的相交区域。 我使用了一种求两个多边形相交的方法

它适用于较小的区域,但对于较大区域的多边形,它开始在交点处显示一些偏移,偏移随着距离的增加而增加。 这也仅适用于具有斜线的多边形(垂直线和水平线的交点似乎工作良好)

我已经为此创建了一个JSFIDLE:

我试图找到黑色和蓝色多边形之间的交点,我得到的是红色多边形,它从应该的位置移动

var mapLayer = L.map('mapid', {
 zoomAnimation: false
});
var pid = 'karan44.pdmio34k';
var at = 'pk.mapbox-access-token-goes-here';
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
  id: pid,
  accessToken: at
}).addTo(mapLayer);

var polygon1 = turf.polygon([
  [
    [3.405762, 51.395350],
    [5.009766, 53.340303],
    [7.141113, 53.653999],
    [5.822754, 51.037508],
    [3.405762, 51.395350]
  ]
], {
  "fill": "#00000F",
  "stroke": "#00000F",
  "stroke-width": 1
});

var polygon2 = turf.polygon([
  [
    [0.241699, 54.173488],
    [10.162354, 50.908012],
    [8.854980, 50.062208],
    [0.241699, 54.173488]
  ]
], {
  "fill": "#0000FF",
  "stroke": "#0000FF",
  "stroke-width": 1
});

var polygon = turf.intersect(polygon1, polygon2);
polygon.properties = {
  "fill": "#FF0000",
  "stroke": "#FF0000",
  "stroke-width": 1
};


L.mapbox.featureLayer().setGeoJSON(polygon1).addTo(mapLayer);
L.mapbox.featureLayer().setGeoJSON(polygon2).addTo(mapLayer);

L.mapbox.featureLayer().setGeoJSON(polygon).addTo(mapLayer);
mapLayer.setView([52.754260888947776, 5.72100021667583], 8);
这把小提琴是通过修改来重现问题的


希望有人能帮助我了解出了什么问题。

这可能是因为(投影的)地图上的直线并不等于地球表面(或者换句话说,在大地水准面上)的直线

有关图形说明,请参阅


我鼓励你用大圆而不是直线来画大多边形,看看交点是否更有意义。

我不清楚草皮在计算交点时做了什么(它们不像伊万所怀疑的那样位于多边形顶点之间的大圆上),但这个问题可以通过沿大圆弧插值多边形,然后在这些圆弧上使用
turp.intersect
来解决。下面的函数将获取GeoJSON多边形(与使用
turp.polygon
生成的多边形类似),并输出新多边形,其中每条边插值为测地线弧(可以选择指定要使用的步骤):

//沿测地弧插值简单的GeoJSON多边形要素
功能测地线(输入,步骤){
如果(步骤类型===‘未定义’){
步长=50;//每个线段上的插值步长
}
变量模板={
“类型”:“功能”,
“几何学”:{
“类型”:“行字符串”,
“坐标”:[]
},
“属性”:{}
}
if(input.geometry.type==“Polygon”){
tempLine.geometry.coordinates=input.geometry.coordinates[0];
tempLine.properties=input.properties;
tempLine.properties.geodesic=“true”;//通知传单.geodesic插值此特征
tempLine.properties.geodesic_步长=步长;
var geoLine=L.geoJson(tempLine).toGeoJSON();//将插值特征转换回geoJson
变量输出={
“类型”:“功能”,
“几何学”:{
“类型”:“多边形”,
“坐标”:geoLine.features[0]。geometry.coordinates
},
“属性”:tempLine.properties
};
output.properties.geodesic=“false”;//防止第二次插值
var outLen=output.geometry.coordinates[0]。长度;
output.geometry.coordinates[0][outLen-1]=output.geometry.coordinates[0][0];
返回输出;
}
log(“测地输入几何体必须是GeoJSON多边形特性”);
返回false;
}
它依赖于,它将插入名为
测地线的属性设置为
“true”
的GeoJSON线字符串特征。这段代码的大部分用于将GeoJSON从多边形转换为线字符串,然后再转换回多边形,如果插件一开始就接受多边形特性,那么这将是不必要的。但无论如何,在您的示例中,您会这样使用它:

var polygon1a=测地线(polygon1,30);
var polygon2a=测地线(polygon2,30);
变量多边形=草皮相交(多边形1a,多边形2a);
polygon.properties={
“填充”:“FF0000”,
“笔划”:“FF0000”,
“笔划宽度”:1
};
L.mapbox.featureLayer().setGeoJSON(polygon1a).addTo(mapLayer);
L.mapbox.featureLayer().setGeoJSON(polygon2a).addTo(mapLayer);
L.mapbox.featureLayer().setGeoJSON(多边形).addTo(映射层);
这是一把小提琴,显示了它的工作原理:

需要注意的是,该函数仅在输入为单个GeoJSON
Polygon
功能时才起作用,尽管它可以适应其他类型。
传单的使用。测地线在这里可能有点过分,但它是有效的。我怀疑任何足够精细的插值实际上都可以很好地工作(即,在地图上绘制时,turf将计算沿多边形边的交点),但这种方法的优点是地理位置正确。

这个问题再次出现,并最终找到了解决方案。分享,以防对其他人有所帮助

我对这个问题的理解是,turf.js和传单js使用不同的投影系统。所以我在传递到TurbJS方法之前,手动将坐标投影到EPSG:3857,然后在传递到传单之前,将TurbJS结果转换回EPSG:4326


看起来问题可能是别的。这里是与传单中一些大圆的比较。测地线:大圆(白色)实际上在地图上向上弯曲,而草皮交叉点向下偏移。感谢@nathansnider分享这个看起来更好的示例,但如果我放大到最大程度,仍然有一个小偏移。从我目前观察到的情况来看,多边形点距离交点越长,偏移量就越大,因为您将其转换为曲线,在曲线之间添加点,减少了多边形点与交点之间的距离,从而减少了偏移量。(或者可能是因为大圆的缘故而正确?)。我需要这是完全相邻的,因为我正在尝试创建连接边完全相同的相邻多边形。也许有另一种方法可以圆化/近似相交线上的这些点?你是正确的,点之间的距离越大,偏移量越大。这个问题显然是草皮中的一个错误,因为计算出的交叉点偏移到了南部,而真正的大圆交叉点实际上位于北部。如果增加步长参数(例如,
geodesify(polygon1100)
),则偏移量可以
var mapLayer = L.map('mapid', {
    zoomAnimation: false
});
var pid = 'karan44.pdmio34k';
var at = 'pk.mapbox-access-token-goes-here';
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
  id: pid,
  accessToken: at
}).addTo(mapLayer);
//Construct Truf projection polygons
var polygon1 = turf.polygon([[
    proj4("EPSG:4326","EPSG:3857",[3.405762, 51.395350]),
    proj4("EPSG:4326","EPSG:3857",[5.009766, 53.340303]),
    proj4("EPSG:4326","EPSG:3857",[7.141113, 53.653999]),
    proj4("EPSG:4326","EPSG:3857",[5.822754, 51.037508]),
    proj4("EPSG:4326","EPSG:3857",[3.405762, 51.395350])
]], {
  "fill": "#00000F",
  "stroke": "#00000F",
  "stroke-width": 1
});
var polygon2 = turf.polygon([[
    proj4("EPSG:4326","EPSG:3857",[0.241699, 54.173488]),
    proj4("EPSG:4326","EPSG:3857",[10.162354, 50.908012]),
    proj4("EPSG:4326","EPSG:3857",[8.854980, 50.062208]),
    proj4("EPSG:4326","EPSG:3857",[0.241699, 54.173488])
]], {
  "fill": "#0000FF",
  "stroke": "#0000FF",
  "stroke-width": 1
});
var polygon = turf.intersect(polygon1, polygon2);
polygon.properties = {
  "fill": "#FF0000",
  "stroke": "#FF0000",
  "stroke-width": 1
};
//Convert all polygons back to Leaflet projection
for(var i in polygon1.geometry.coordinates[0]) {
    polygon1.geometry.coordinates[0][i] = proj4("EPSG:3857","EPSG:4326",polygon1.geometry.coordinates[0][i]);
}
for(var i in polygon2.geometry.coordinates[0]) {
    polygon2.geometry.coordinates[0][i] = proj4("EPSG:3857","EPSG:4326",polygon2.geometry.coordinates[0][i]);
}
for(var i in polygon.geometry.coordinates[0]) {
    polygon.geometry.coordinates[0][i] = proj4("EPSG:3857","EPSG:4326",polygon.geometry.coordinates[0][i]);
}
L.mapbox.featureLayer().setGeoJSON(polygon1).addTo(mapLayer);
L.mapbox.featureLayer().setGeoJSON(polygon2).addTo(mapLayer);
L.mapbox.featureLayer().setGeoJSON(polygon).addTo(mapLayer);
mapLayer.setView([52.754260888947776, 5.72100021667583], 8);