-->

Check if a polygon point is inside another in leaf

2019-04-24 09:17发布

问题:

I'm having two sets of polygon coordinates selected from leaflet geoJSON map. The parent and child coordinates are coordinates are:

var parentCoordinates=[
    [
        32.05898221582174,
        -28.31004731142091
    ],
    [
        32.05898221582174,
        -28.308044824292978
    ],
    [
        32.06134255975485,
        -28.308044824292978
    ],
    [
        32.06134255975485,
        -28.31004731142091
    ],
    [
        32.05898221582174,
        -28.31004731142091
    ]
]
var childCoordinates=[
  [
    32.059904895722866,
    -28.30970726909422
  ],
  [
    32.059904895722866,
    -28.308743809931784
  ],
  [
    32.06089194864035,
    -28.308743809931784
  ],
  [
    32.06089194864035,
    -28.30970726909422
  ],
  [
    32.059904895722866,
    -28.30970726909422
  ]
]

The child is drawn inside the parent area as shown in the picture:

Using Ray Casting algorithm to determine if the point lies inside polygon I 'm not able to determine as the result I'm getting is false. Please let me know where I'm doing wrong or any other way to determine the solution.Thanks

回答1:

I tried with your algorithm and another found here https://rosettacode.org/wiki/Ray-casting_algorithm and both return the right value.

Maybe this fiddle can help you in the implementation :

https://jsfiddle.net/4psL2hoo/1/

Your algo

// Data
var parentCoordinates=[
    [
        32.05898221582174,
        -28.31004731142091
    ],
    [
        32.05898221582174,
        -28.308044824292978
    ],
    [
        32.06134255975485,
        -28.308044824292978
    ],
    [
        32.06134255975485,
        -28.31004731142091
    ],
    [
        32.05898221582174,
        -28.31004731142091
    ]
]
var childCoordinates=[
  [
    32.059904895722866,
    -28.30970726909422
  ],
  [
    32.059904895722866,
    -28.308743809931784
  ],
  [
    32.06089194864035,
    -28.308743809931784
  ],
  [
    32.06089194864035,
    -28.30970726909422
  ],
  [
    32.059904895722866,
    -28.30970726909422
  ]
]

// Other algo
function test(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;
};

for (var i = 0; i < childCoordinates.length; i++) {
     var testPoint = childCoordinates[i];
     console.log(JSON.stringify(testPoint) + '\tin parentCoordinate\t' + test(testPoint, parentCoordinates));
}

Rosetta code algo

//https://rosettacode.org/wiki/Ray-casting_algorithm
function contains(bounds, lat, lng) {
    //https://rosettacode.org/wiki/Ray-casting_algorithm
    var count = 0;
    for (var b = 0; b < bounds.length; b++) {
        var vertex1 = bounds[b];
        var vertex2 = bounds[(b + 1) % bounds.length];
        if (west(vertex1, vertex2, lng, lat))
            ++count;
    }
    return count % 2;

    /**
     * @return {boolean} true if (x,y) is west of the line segment connecting A and B
     */
    function west(A, B, x, y) {
        if (A.y <= B.y) {
            if (y <= A.y || y > B.y ||
                x >= A.x && x >= B.x) {
                return false;
            } else if (x < A.x && x < B.x) {
                return true;
            } else {
                return (y - A.y) / (x - A.x) > (B.y - A.y) / (B.x - A.x);
            }
        } else {
            return west(B, A, x, y);
        }
    }
}

var square = {name: 'square', bounds: [{x: 32.05898221582174, y: -28.31004731142091}, {x: 32.05898221582174, y: -28.308044824292978}, {x: 32.06134255975485, y: -28.308044824292978}, {x: 32.06134255975485, y: -28.31004731142091}]};

var shapes = [square];
var testPoints = [{lng: 32.059904895722866, lat: -28.30970726909422}, {lng: 32.059904895722866, lat: -28.308743809931784}, {lng: 32.06089194864035, lat: -28.308743809931784},
    {lng: 32.06089194864035, lat: -28.30970726909422}];

for (var s = 0; s < shapes.length; s++) {
    var shape = shapes[s];
    for (var tp = 0; tp < testPoints.length; tp++) {
        var testPoint = testPoints[tp];
        console.log(JSON.stringify(testPoint) + '\tin ' + shape.name + '\t' + contains(shape.bounds, testPoint.lat, testPoint.lng));
    }
}


回答2:

I've had good experience with Turf. It works well, is well documented and the examples are already shown with leaflet.

For your problem, you could use turf.within with parentCoordinates as turf.polygon and childCoordinates as an array of turf.point :

var parentPolygon = turf.polygon([parentCoordinates]);

var inside = true;
childCoordinates.forEach(function(coordinates) {
    point = turf.point(coordinates);
    if (!turf.inside(point, parentPolygon)){
      alert("Oh no! "+ coordinates + " isn't in polygon");
      inside = false;
    }
});

alert("Child polygon inside parent polygon ? " + inside);

Here's a Fiddle example.



回答3:

You can try Leaflet's api for that - contains . You create a parent polygon with LatLngBounds and then child too.

parentPolygon.contains(childPolygon)