[英]Check if Point Is Inside A Polygon
我想检查一个点是否位于特定的多边形内。 多边形是:
polygon= [ [-73.89632720118, 40.8515320489962],
[-73.8964878416508, 40.8512476593594],
[-73.8968799791431, 40.851375925454],
[-73.8967188588015, 40.851660158514],
[-73.89632720118, 40.8515320489962] ]
我要检查的要点是:
1 = [40.8515320489962,-73.89632720118]
2 = [40.8512476593594,-73.8964878416508]
3 = [40.851375925454,-73.8968799791431]
4 = [40.851660158514,-73.8967188588015]
5 = [40.8515320489962,-73.89632720118]
如何判断这些点中的每一个是否都位于该多边形内?
下面的算法不起作用。 我不知道为什么。
pt[lat,long]
function isPointInPoly(poly, pt){
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1] < poly[i][1]))
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
&& (c = !c);
return c;
}
我不想使用第三方解决方案,例如 google maps API 或这个https://github.com/mattwilliamson/Google-Maps-Point-in-Polygon 。
我的尝试在这里:http: //jsfiddle.net/nvNNF/2/
Github 上有一个项目代码: https ://github.com/substack/point-in-polygon(MIT 许可):
function inside(point, vs) {
// ray-casting algorithm based on
// https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html/pnpoly.html
var x = point[0], y = point[1];
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i][0], yi = vs[i][1];
var xj = vs[j][0], yj = vs[j][1];
var intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
用法:
// array of coordinates of each vertex of the polygon
var polygon = [ [ 1, 1 ], [ 1, 2 ], [ 2, 2 ], [ 2, 1 ] ];
inside([ 1.5, 1.5 ], polygon); // true
测试功能在这里: https ://github.com/substack/point-in-polygon/blob/master/index.js
注意:当点是多边形的角或边缘时,此代码不能可靠地工作。 这里有一个改进的版本: https ://github.com/mikolalysenko/robust-point-in-polygon
您的多边形数组看起来像 GeoJSON 多边形结构中的coordinates
数组(在https://macwright.org/2015/03/23/geojson-second-bite.html和http://geojson.org阅读更多内容)。 所以也许你可以使用处理 geoJSON 数据的库? 查看对 OP 的回答和评论是否可以使用 JavaScript 确定 GeoJSON 点是否在 GeoJSON 多边形内?
简而言之,我的一天被turf
( https://github.com/turfjs/turf )拯救了还有d3
( https://github.com/d3/d3-geo#geoContains ),但我遇到了问题。
UPD:我注意到当点位于多边形的“边缘”时, turf
给出的结果不一致。 我创建了问题,正在等待开发人员的回答。
UPD2:使用最新版本的turf
解决了“边界点”问题(我使用的是 3.0.14 而不是 4.6.1)。 现在没事了。
这是我终于开始工作的功能。 我通过从这里采用 C 代码到 javascript 得到它(附有解释)。
function checkcheck (x, y, cornersX, cornersY) {
var i, j=cornersX.length-1 ;
var odd = false;
var pX = cornersX;
var pY = cornersY;
for (i=0; i<cornersX.length; i++) {
if ((pY[i]< y && pY[j]>=y || pY[j]< y && pY[i]>=y)
&& (pX[i]<=x || pX[j]<=x)) {
odd ^= (pX[i] + (y-pY[i])*(pX[j]-pX[i])/(pY[j]-pY[i])) < x;
}
j=i;
}
return odd;
}
其中cornersX
=带有x或纬度顶点数组的数组, cornersY
=带有y或经度数组的数组。 X, Y - 测试点的纬度和经度。
就我而言,我做了以下事情,这对我来说很好
function isLatLngInZone(latLngs,lat,lng){
// latlngs = [{"lat":22.281610498720003,"lng":70.77577162868579},{"lat":22.28065743343672,"lng":70.77624369747241},{"lat":22.280860953131217,"lng":70.77672113067706},{"lat":22.281863655593973,"lng":70.7762061465462}];
vertices_y = new Array();
vertices_x = new Array();
longitude_x = lng;
latitude_y = lat;
latLngs = JSON.parse(latLngs);
var r = 0;
var i = 0;
var j = 0;
var c = 0;
var point = 0;
for(r=0; r<latLngs.length; r++){
vertices_y.push(latLngs[r].lat);
vertices_x.push(latLngs[r].lng);
}
points_polygon = vertices_x.length;
for(i = 0, j = points_polygon; i < points_polygon; j = i++){
point = i;
if(point == points_polygon)
point = 0;
if ( ((vertices_y[point] > latitude_y != (vertices_y[j] > latitude_y)) && (longitude_x < (vertices_x[j] - vertices_x[point]) * (latitude_y - vertices_y[point]) / (vertices_y[j] - vertices_y[point]) + vertices_x[point]) ) )
c = !c;
}
return c;
}
@AaronDigulla的答案是最好的,没有附加库,下面是一个简短的版本,将点分解为[x,y]。 下面的答案包括在绕线数测试之前的boundingBox测试。 性能降低了20%(jsperf),但效果很好,并且可读性更高。
function matchPointAndPolygon(point,polygon) {
const bbox = poly => poly.reduce((b,[x,y]) =>
({"miX":Math.min(x,b.miX),"maX":Math.max(x,b.maX),"miY":Math.min(y,b.miY),"maY":Math.max(y,b.maY)}),
{"miX":poly[0][0],"maX":poly[0][0], "miY":poly[0][1],"maY":poly[0][1]});
const inBBox = ([x,y], box) => !(x < box.miX || x > box.maX || y < box.miY || y > box.maY);
const intersect = (xi,yi, xj,yj, u,v) =>
((yi > v) != (yj > v)) && (u < (xj - xi) * (v - yi) / (yj - yi) + xi);
const nex = (i,t) => i===0? t.length-1 : i-1;
const insideWN = ([x,y], vs) => !!(vs.reduce((s,p,i,t) =>
s + intersect(p[0],p[1], t[nex(i,t)][0],t[nex(i,t)][1], x,y), 0));
return inBBox(point, bbox(polygon)) && insideWN(point, polygon);
}
//Usage:
const ins = pointsToCheck.map(p => matchPointAndPolygon(p, polygon));
注意:它适用于“ geojson”多边形格式,其中最后一点重复第一个点。
注意2:我使用的是OpenLayers API的专用功能,但在Web工作程序中,插入该“简易”版本会更容易。
我根据Aaron 的回答对功能进行了现代化改造:
const getIsPointInsidePolygon = (point: number[], vertices: number[][]) => {
const x = point[0]
const y = point[1]
let inside = false
for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
const xi = vertices[i][0],
yi = vertices[i][1]
const xj = vertices[j][0],
yj = vertices[j][1]
const intersect = yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi
if (intersect) inside = !inside
}
return inside
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.