检查点是否在多边形内

时间:2014-03-20 02:00:51

标签: javascript

我想检查点是否位于特定多边形内。多边形是:

 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].y))
        && (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/

5 个答案:

答案 0 :(得分:76)

Github上有一个项目,代码为:https://github.com/substack/point-in-polygon(MIT许可证):

function inside(point, vs) {
    // ray-casting algorithm based on
    // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/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

答案 1 :(得分:9)

这是我终于开始工作的功能。我通过从here采用C代码到javascript来获得它(带解释)。

function checkcheck (x, y, cornersX, cornersY) {

    var i, j=cornersX.length-1 ;
    var  oddNodes=false;

    var polyX = cornersX;
    var polyY = cornersY;

    for (i=0; i<cornersX.length; i++) {
        if ((polyY[i]< y && polyY[j]>=y ||  polyY[j]< y && polyY[i]>=y) &&  (polyX[i]<=x || polyX[j]<=x)) {
oddNodes^=(polyX[i]+(y-polyY[i])/(polyY[j]-polyY[i])*(polyX[j]-polyX[i])<x); 
        }

    j=i; 
    }

return oddNodes;
}

其中cornersX =具有x或纬度顶点数组的数组,cornersY =具有y或经度数组的数组。 X,Y - 测试点的纬度和经度。

答案 2 :(得分:8)

您的多边形数组在GeoJSON多边形结构中看起来像coordinates数组(在https://macwright.org/2015/03/23/geojson-second-bite.htmlhttp://geojson.org处阅读更多内容)。 那么也许您可以使用使用geoJSON数据的库?在Is it possible to determine if a GeoJSON point is inside a GeoJSON polygon using JavasScript?

中查看对答案的评论和评论

简而言之,turfhttps://github.com/turfjs/turf)保存了我的一天 还有d3https://github.com/d3/d3-geo#geoContains),但我遇到了问题。

UPD: 当点在多边形的“边缘”上时,我注意到turf给出了不一致的结果。我创建了问题,我正在等待开发人员的回答。

UPD2: “边界点”问题通过使用最新版本的turf来解决(我使用的是3.0.14而不是4.6.1)。现在好了。

答案 3 :(得分:0)

就我而言,我确实做了以下事情,对我来说很好用

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

答案 4 :(得分:0)

@AaronDigulla的答案是最好的,没有附加库,下面是一个较短的版本,将点分解为[x,y]。下面的答案包括在绕线数测试之前的boundingBox测试。性能降低了(jsperf)20%,但效果很好,而且可读性更高。

SELECT  parts.* FROM parts
LEFT OUTER JOIN galleries
ON galleries.part_id = parts.id
LEFT OUTER JOIN images ON images.gallery_id = galleries.id
GROUP BY parts.id
ORDER BY parts.sale_rotation_group DESC, COUNT(images.id) DESC, parts.parameters_count DESC

注意:它使用“ geojson”多边形格式,其中最后一点重复第一个点。

注意2:我使用的是OpenLayers API的专用功能,但是在Web工作人员中,插入“轻量”版本会更容易。