Properly fix detection of 'point in polygon' with multipolygons, fixes GRB display issue
This commit is contained in:
parent
08efcbdea0
commit
31024c5074
1 changed files with 51 additions and 48 deletions
|
@ -124,6 +124,20 @@ export class GeoOperations {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static pointInPolygonCoordinates(x: number, y: number, coordinates: [number, number][][]) {
|
||||||
|
const inside = GeoOperations.pointWithinRing(x, y, /*This is the outer ring of the polygon */coordinates[0])
|
||||||
|
if (!inside) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let i = 1; i < coordinates.length; i++) {
|
||||||
|
const inHole = GeoOperations.pointWithinRing(x, y, coordinates[i] /* These are inner rings, aka holes*/)
|
||||||
|
if (inHole) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static inside(pointCoordinate, feature): boolean {
|
public static inside(pointCoordinate, feature): boolean {
|
||||||
// ray-casting algorithm based on
|
// ray-casting algorithm based on
|
||||||
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
||||||
|
@ -136,62 +150,31 @@ export class GeoOperations {
|
||||||
pointCoordinate = pointCoordinate.geometry.coordinates
|
pointCoordinate = pointCoordinate.geometry.coordinates
|
||||||
}
|
}
|
||||||
|
|
||||||
if (feature.geometry.type === "MultiPolygon") {
|
|
||||||
const coordinates = feature.geometry.coordinates[0];
|
|
||||||
const outerPolygon = coordinates[0];
|
|
||||||
const inside = GeoOperations.inside(pointCoordinate, {
|
|
||||||
geometry: {
|
|
||||||
type: 'Polygon',
|
|
||||||
coordinates: [outerPolygon]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (!inside) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (let i = 1; i < coordinates.length; i++) {
|
|
||||||
const inHole = GeoOperations.inside(pointCoordinate, {
|
|
||||||
geometry: {
|
|
||||||
type: 'Polygon',
|
|
||||||
coordinates: [coordinates[i]]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (inHole) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const x: number = pointCoordinate[0];
|
const x: number = pointCoordinate[0];
|
||||||
const y: number = pointCoordinate[1];
|
const y: number = pointCoordinate[1];
|
||||||
|
|
||||||
for (let i = 0; i < feature.geometry.coordinates.length; i++) {
|
|
||||||
let poly = feature.geometry.coordinates[i];
|
|
||||||
|
|
||||||
let inside = false;
|
if (feature.geometry.type === "MultiPolygon") {
|
||||||
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
|
const coordinatess = feature.geometry.coordinates;
|
||||||
const coori = poly[i];
|
for (const coordinates of coordinatess) {
|
||||||
const coorj = poly[j];
|
const inThisPolygon = GeoOperations.pointInPolygonCoordinates(x, y, coordinates)
|
||||||
|
if (inThisPolygon) {
|
||||||
const xi = coori[0];
|
return true;
|
||||||
const yi = coori[1];
|
|
||||||
const xj = coorj[0];
|
|
||||||
const yj = coorj[1];
|
|
||||||
|
|
||||||
const intersect = ((yi > y) != (yj > y))
|
|
||||||
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
|
||||||
if (intersect) {
|
|
||||||
inside = !inside;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (inside) {
|
return false;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
if (feature.geometry.type === "Polygon") {
|
||||||
|
return GeoOperations.pointInPolygonCoordinates(x, y, feature.geometry.coordinates)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw "GeoOperations.inside: unsupported geometry type"
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static lengthInMeters(feature: any) {
|
static lengthInMeters(feature: any) {
|
||||||
return turf.length(feature) * 1000
|
return turf.length(feature) * 1000
|
||||||
|
@ -587,6 +570,26 @@ export class GeoOperations {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static pointWithinRing(x: number, y: number, ring: [number, number][]) {
|
||||||
|
let inside = false;
|
||||||
|
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
||||||
|
const coori = ring[i];
|
||||||
|
const coorj = ring[j];
|
||||||
|
|
||||||
|
const xi = coori[0];
|
||||||
|
const yi = coori[1];
|
||||||
|
const xj = coorj[0];
|
||||||
|
const yj = coorj[1];
|
||||||
|
|
||||||
|
const intersect = ((yi > y) != (yj > y))
|
||||||
|
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
|
||||||
|
if (intersect) {
|
||||||
|
inside = !inside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inside;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the intersection between two features.
|
* Calculates the intersection between two features.
|
||||||
* Returns the length if intersecting a linestring and a (multi)polygon (in meters), returns a surface area (in m²) if intersecting two (multi)polygons
|
* Returns the length if intersecting a linestring and a (multi)polygon (in meters), returns a surface area (in m²) if intersecting two (multi)polygons
|
||||||
|
|
Loading…
Reference in a new issue