From 2049430b0079bfd0d7e739edb9e20a80df1bbdf6 Mon Sep 17 00:00:00 2001 From: Pitouli Date: Sat, 18 Jan 2025 18:04:43 +0100 Subject: [PATCH 1/2] Improve performances of booleanPointInPolygon with MultiPolygons Optimize booleanPointInPolygon to return "true" as soon as one polygon contains the point instead of looping over all the polygons --- packages/turf-boolean-point-in-polygon/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/turf-boolean-point-in-polygon/index.ts b/packages/turf-boolean-point-in-polygon/index.ts index b383cd9b8d..e17c40908b 100644 --- a/packages/turf-boolean-point-in-polygon/index.ts +++ b/packages/turf-boolean-point-in-polygon/index.ts @@ -68,14 +68,14 @@ function booleanPointInPolygon< if (type === "Polygon") { polys = [polys]; } - let result = false; + for (var i = 0; i < polys.length; ++i) { const polyResult = pip(pt, polys[i]); if (polyResult === 0) return options.ignoreBoundary ? false : true; - else if (polyResult) result = true; + else if (polyResult) return true; } - return result; + return false; } /** From 69d6d712fbcbbc7b7512bfb34106f3a106412623 Mon Sep 17 00:00:00 2001 From: Pitouli Date: Sat, 18 Jan 2025 17:33:58 +0000 Subject: [PATCH 2/2] Fix edge case for booleanPointInPolygon when point is on border of a polygon and inside another one --- .../turf-boolean-point-in-polygon/index.ts | 5 +++- .../turf-boolean-point-in-polygon/test.ts | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/turf-boolean-point-in-polygon/index.ts b/packages/turf-boolean-point-in-polygon/index.ts index e17c40908b..121cf6d0ae 100644 --- a/packages/turf-boolean-point-in-polygon/index.ts +++ b/packages/turf-boolean-point-in-polygon/index.ts @@ -71,7 +71,10 @@ function booleanPointInPolygon< for (var i = 0; i < polys.length; ++i) { const polyResult = pip(pt, polys[i]); - if (polyResult === 0) return options.ignoreBoundary ? false : true; + // If being on the boundary doesn't count, stay in the loop to see if we're inside another polygon + // The RFC does not prevent polygons from overlapping; https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.7 + if (polyResult === 0 && !options.ignoreBoundary) return true; + // If point is in the polygon, exit early the loop else if (polyResult) return true; } diff --git a/packages/turf-boolean-point-in-polygon/test.ts b/packages/turf-boolean-point-in-polygon/test.ts index 113e216574..9296694f2b 100644 --- a/packages/turf-boolean-point-in-polygon/test.ts +++ b/packages/turf-boolean-point-in-polygon/test.ts @@ -2,7 +2,7 @@ import fs from "fs"; import path from "path"; import { fileURLToPath } from "url"; import test from "tape"; -import { point } from "@turf/helpers"; +import { multiPolygon, point } from "@turf/helpers"; import { polygon } from "@turf/helpers"; import { booleanPointInPolygon } from "./index.js"; @@ -143,6 +143,26 @@ test("boolean-point-in-polygon -- Boundary test", function (t) { [10, 20], ], ]); + var poly6 = multiPolygon([ + [ + [ + [10, 20], + [20, 10], + [30, 20], + [20, 30], + [10, 20], + ], + ], + [ + [ + [0, 20], + [20, 0], + [40, 20], + [20, 40], + [0, 20], + ], + ], + ]); function runTest(t, ignoreBoundary) { var isBoundaryIncluded = ignoreBoundary === false; var tests = [ @@ -183,6 +203,7 @@ test("boolean-point-in-polygon -- Boundary test", function (t) { [poly5, point([10, 20]), isBoundaryIncluded], [poly5, point([15, 25]), isBoundaryIncluded], [poly5, point([20, 20]), false], + [poly6, point([25, 25]), true], // Point on the boundary of the first polygon, but inside the second polygon ]; var testTitle =