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

时间:2016-04-19 11:34:22

标签: leaflet mapbox turfjs

我试图找到地图上绘制的2个多边形之间的交叉区域。 我用TurfJS交叉方法找到2个多边形之间的交点。

它适用于较小的区域,但对于较大面积的多边形,它会在交叉点处开始显示一些偏移,偏移量随着距离的增加而增加。 这也仅适用于具有斜线的多边形(垂直和水平线交叉点看起来效果很好)。

我为此创建了一个JSFiddle:https://jsfiddle.net/cLe6yo9d/

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

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);

这个小提琴是通过修改turf.intersect example来重现问题而创建的。

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

3 个答案:

答案 0 :(得分:1)

我不清楚草坪在计算交叉点时是做什么的(它们不像Ivan所怀疑的那样位于多边形顶点之间的大圆上),但问题可以通过插入多边形来解决大圆弧,然后在那些上使用 public static List<SelectListItem> GetLateralities() { return new List<SelectListItem> { new SelectListItem { Text = "", Value = "900" }, new SelectListItem { Text = "Left", Value = "1001" }, new SelectListItem { Text = "Right", Value = "1002" }, new SelectListItem { Text = "Midline", Value = "1003" }, new SelectListItem { Text = "Left Midline", Value = "1004" }, new SelectListItem { Text = "Right Midline",Value = "1005" }, new SelectListItem { Text = "Both Sides", Value = "1006" }, new SelectListItem { Text = "Unknown", Value = "990" }, new SelectListItem { Text = "Unspecified", Value = "997" }, new SelectListItem { Text = "N/A", Value = "999" }, }; } 。下面的函数将采用GeoJSON多边形(如使用turf.intersect生成的那些多边形)并输出新多边形,每个边插值为一个测地弧(可选择指定要使用的步骤数):

turf.polygon

它依赖于Leaflet.Geodesic plugin,它将插入GeoJSON LineString功能,这些功能将//interpolates simple GeoJSON polygon features along geodesic arcs function geodesify(input, steps) { if (typeof steps === 'undefined') { steps = 50; //interpolation steps on each segment } var tempLine = { "type": "Feature", "geometry": { "type": "LineString", "coordinates": [] }, "properties": {} } if (input.geometry.type === "Polygon") { tempLine.geometry.coordinates = input.geometry.coordinates[0]; tempLine.properties = input.properties; tempLine.properties.geodesic = "true"; //tells Leaflet.Geodesic to interpolate this feature tempLine.properties.geodesic_steps = steps; var geoLine = L.geoJson(tempLine).toGeoJSON();//convert interpolated feature back to GeoJSON var output = { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": geoLine.features[0].geometry.coordinates }, "properties": tempLine.properties }; output.properties.geodesic = "false"; //to prevent a second interpolation var outLen = output.geometry.coordinates[0].length; output.geometry.coordinates[0][outLen-1] = output.geometry.coordinates[0][0]; return output; } console.log("geodesify input geometry must be a GeoJSON Polygon Feature"); return false; } 属性设置为geodesic。大部分代码用于将GeoJSON从Polygon转换为LineString并返回到Polygon,如果插件接受Polygon功能,则不需要这样做。但无论如何,在你的例子中,你会像这样使用它:

"true"

这是一个在工作中表现出来的小提琴:

https://jsfiddle.net/nathansnider/ycnno5df/

重要的是要注意,此功能仅在输入是单个GeoJSON var polygon1a = geodesify(polygon1, 30); var polygon2a = geodesify(polygon2, 30); var polygon = turf.intersect(polygon1a, polygon2a); polygon.properties = { "fill": "#FF0000", "stroke": "#FF0000", "stroke-width": 1 }; L.mapbox.featureLayer().setGeoJSON(polygon1a).addTo(mapLayer); L.mapbox.featureLayer().setGeoJSON(polygon2a).addTo(mapLayer); L.mapbox.featureLayer().setGeoJSON(polygon).addTo(mapLayer); 功能时才有效,尽管它可以适用于其他类型。 Leaflet.Geodesic的使用在这里可能有些过分,但它确实有效。我怀疑任何足够精细的插值实际上都能正常工作(也就是说,草皮会计算在地图上绘制时沿多边形边缘落下的交点),但这种方法具有地理上正确的优点。

答案 1 :(得分:1)

这个问题又回来了,终于找到了解决方案。分享以防万一可能对其他人有帮助。

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

https://jsfiddle.net/5Ls3vw8d/

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);

答案 2 :(得分:0)

这可能是因为(投影)地图上的直线不等于地球表面上的直线(换句话说,在大地水准面的面上是great circles)。 / p>

有关图形说明,请参阅some great circles

我鼓励你用大圆圈而不是线条绘制你的大多边形,看看交叉点是否更有意义。