From 4c4e19724a0e8218ad625798ff80e2ffc2a88883 Mon Sep 17 00:00:00 2001 From: AminoffZ Date: Sun, 22 Oct 2023 13:54:13 +0300 Subject: [PATCH 1/5] Merge pull request #1387 from pirxpilot:area --- packages/turf-area/index.ts | 82 +++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/packages/turf-area/index.ts b/packages/turf-area/index.ts index 8277d15303..4b50c223be 100644 --- a/packages/turf-area/index.ts +++ b/packages/turf-area/index.ts @@ -67,6 +67,15 @@ function polygonArea(coords: any) { return total; } +/** + * @private + * A constant factor used to compute the area of a polygon. + * It's derived from the square of the Earth's radius divided by 2. + * + * @type {number} + */ +const FACTOR = (earthRadius * earthRadius) / 2; + /** * @private * Calculate the approximate area of the polygon were it projected onto the earth. @@ -81,43 +90,46 @@ function polygonArea(coords: any) { * @returns {number} The approximate signed geodesic area of the polygon in square meters. */ function ringArea(coords: number[][]) { - let p1; - let p2; - let p3; - let lowerIndex; - let middleIndex; - let upperIndex; - let i; - let total = 0; - const coordsLength = coords.length; - - if (coordsLength > 2) { - for (i = 0; i < coordsLength; i++) { - if (i === coordsLength - 2) { - // i = N-2 - lowerIndex = coordsLength - 2; - middleIndex = coordsLength - 1; - upperIndex = 0; - } else if (i === coordsLength - 1) { - // i = N-1 - lowerIndex = coordsLength - 1; - middleIndex = 0; - upperIndex = 1; - } else { - // i = 0 to N-3 - lowerIndex = i; - middleIndex = i + 1; - upperIndex = i + 2; - } - p1 = coords[lowerIndex]; - p2 = coords[middleIndex]; - p3 = coords[upperIndex]; - total += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1])); + // it's a ring - ignore the last one + const coordsLength = coords.length - 1; + + if (coordsLength < 3) { + return 0; } - total = (total * earthRadius * earthRadius) / 2; - } - return total; + let total = 0; + + const f_x = rad(coords[0][0]), f_y = rad(coords[0][1]); + const s_x = rad(coords[1][0]), s_y = rad(coords[1][1]); + + let l_x = f_x, l_y = f_y; + let m_x = s_x, m_y = s_y; + + let u_x = 0, u_y = 0; + + for (let i = 2; i < coordsLength; i++) { + u_x = rad(coords[i][0]); u_y = rad(coords[i][1]); + + total += (u_x - l_x) * Math.sin(m_y); + + l_x = m_x; l_y = m_y; + m_x = u_x; m_y = u_y; + } + + // handle 2 extra triangles (since we started from i = 2) + + u_x = f_x; u_y = f_y; + + total += (u_x - l_x) * Math.sin(m_y); + + l_x = m_x; l_y = m_y; + m_x = u_x; m_y = u_y; + + u_x = s_x; u_y = s_y; + + total += (u_x - l_x) * Math.sin(m_y); + + return total * FACTOR; } function rad(num: number) { From 7c5d3824e2972b7012191be67e36549798fdcb24 Mon Sep 17 00:00:00 2001 From: AminoffZ Date: Sun, 22 Oct 2023 14:15:00 +0300 Subject: [PATCH 2/5] Fix optimized ringArea --- packages/turf-area/index.ts | 65 +++++++++++++++---------------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/packages/turf-area/index.ts b/packages/turf-area/index.ts index 4b50c223be..0bfa513529 100644 --- a/packages/turf-area/index.ts +++ b/packages/turf-area/index.ts @@ -76,6 +76,15 @@ function polygonArea(coords: any) { */ const FACTOR = (earthRadius * earthRadius) / 2; +/** + * @private + * A constant used for converting degrees to radians. + * Represents the ratio of PI to 180. + * + * @type {number} + */ +const PI_OVER_180 = Math.PI / 180; + /** * @private * Calculate the approximate area of the polygon were it projected onto the earth. @@ -89,49 +98,27 @@ const FACTOR = (earthRadius * earthRadius) / 2; * @param {Array>} coords Ring Coordinates * @returns {number} The approximate signed geodesic area of the polygon in square meters. */ -function ringArea(coords: number[][]) { - // it's a ring - ignore the last one - const coordsLength = coords.length - 1; - - if (coordsLength < 3) { - return 0; - } - - let total = 0; - - const f_x = rad(coords[0][0]), f_y = rad(coords[0][1]); - const s_x = rad(coords[1][0]), s_y = rad(coords[1][1]); - - let l_x = f_x, l_y = f_y; - let m_x = s_x, m_y = s_y; - - let u_x = 0, u_y = 0; - - for (let i = 2; i < coordsLength; i++) { - u_x = rad(coords[i][0]); u_y = rad(coords[i][1]); - - total += (u_x - l_x) * Math.sin(m_y); - - l_x = m_x; l_y = m_y; - m_x = u_x; m_y = u_y; - } - - // handle 2 extra triangles (since we started from i = 2) - - u_x = f_x; u_y = f_y; +function ringArea(coords: number[][]): number { + let total = 0; + const coordsLength = coords.length; - total += (u_x - l_x) * Math.sin(m_y); + if (coordsLength <= 2) return 0; - l_x = m_x; l_y = m_y; - m_x = u_x; m_y = u_y; + let i = 0; + while (i < coordsLength) { + const lower = coords[i]; + const middle = coords[i + 1 === coordsLength ? 0 : i + 1]; + const upper = + coords[i + 2 >= coordsLength ? (i + 2) % coordsLength : i + 2]; - u_x = s_x; u_y = s_y; + const lowerX = lower[0] * PI_OVER_180; + const middleY = middle[1] * PI_OVER_180; + const upperX = upper[0] * PI_OVER_180; - total += (u_x - l_x) * Math.sin(m_y); + total += (upperX - lowerX) * Math.sin(middleY); - return total * FACTOR; -} + i++; + } -function rad(num: number) { - return (num * Math.PI) / 180; + return total * FACTOR; } From b01fd4915beafaf827062280129ca4afcb4f8afc Mon Sep 17 00:00:00 2001 From: AminoffZ Date: Sun, 22 Oct 2023 21:38:59 +0300 Subject: [PATCH 3/5] Regen nearest-neighbor-analysis --- packages/turf-area/index.ts | 2 +- .../turf-nearest-neighbor-analysis/test/out/squares.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/turf-area/index.ts b/packages/turf-area/index.ts index 0bfa513529..d6bbfd1257 100644 --- a/packages/turf-area/index.ts +++ b/packages/turf-area/index.ts @@ -99,10 +99,10 @@ const PI_OVER_180 = Math.PI / 180; * @returns {number} The approximate signed geodesic area of the polygon in square meters. */ function ringArea(coords: number[][]): number { - let total = 0; const coordsLength = coords.length; if (coordsLength <= 2) return 0; + let total = 0; let i = 0; while (i < coordsLength) { diff --git a/packages/turf-nearest-neighbor-analysis/test/out/squares.json b/packages/turf-nearest-neighbor-analysis/test/out/squares.json index 745478f8fe..66efc1a2ad 100644 --- a/packages/turf-nearest-neighbor-analysis/test/out/squares.json +++ b/packages/turf-nearest-neighbor-analysis/test/out/squares.json @@ -1473,10 +1473,10 @@ "units": "kilometers", "arealUnits": "kilometers²", "observedMeanDistance": 4.986280150858801, - "expectedMeanDistance": 2.496567669388766, - "nearestNeighborIndex": 1.997254154973332, + "expectedMeanDistance": 2.4965676693887655, + "nearestNeighborIndex": 1.9972541549733325, "numberOfPoints": 56, - "zScore": 14.27679589626176 + "zScore": 14.276795896261763 } }, "geometry": { From 19c4107177f9cd006382cc9624332aa0d21cff9a Mon Sep 17 00:00:00 2001 From: AminoffZ Date: Sun, 22 Oct 2023 22:03:58 +0300 Subject: [PATCH 4/5] Add rest of out tests --- .../test/out/random-large-study-area.json | 6 +++--- .../test/out/random-outlier.json | 6 +++--- .../turf-nearest-neighbor-analysis/test/out/random.json | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/turf-nearest-neighbor-analysis/test/out/random-large-study-area.json b/packages/turf-nearest-neighbor-analysis/test/out/random-large-study-area.json index cc35013876..f66a328005 100644 --- a/packages/turf-nearest-neighbor-analysis/test/out/random-large-study-area.json +++ b/packages/turf-nearest-neighbor-analysis/test/out/random-large-study-area.json @@ -1211,10 +1211,10 @@ "units": "kilometers", "arealUnits": "kilometers²", "observedMeanDistance": 1.6516270145942438, - "expectedMeanDistance": 25.461470908340697, - "nearestNeighborIndex": 0.06486769835646855, + "expectedMeanDistance": 25.46147090834068, + "nearestNeighborIndex": 0.0648676983564686, "numberOfPoints": 150, - "zScore": -21.910362919163752 + "zScore": -21.91036291916375 } }, "geometry": { diff --git a/packages/turf-nearest-neighbor-analysis/test/out/random-outlier.json b/packages/turf-nearest-neighbor-analysis/test/out/random-outlier.json index 9bf4d0d698..5425cbb31f 100644 --- a/packages/turf-nearest-neighbor-analysis/test/out/random-outlier.json +++ b/packages/turf-nearest-neighbor-analysis/test/out/random-outlier.json @@ -1220,10 +1220,10 @@ "units": "kilometers", "arealUnits": "kilometers²", "observedMeanDistance": 7.363991103875287, - "expectedMeanDistance": 25.37702057977424, - "nearestNeighborIndex": 0.29018343901823007, + "expectedMeanDistance": 25.377020579774225, + "nearestNeighborIndex": 0.29018343901823024, "numberOfPoints": 151, - "zScore": -16.68650889595032 + "zScore": -16.686508895950315 } }, "geometry": { diff --git a/packages/turf-nearest-neighbor-analysis/test/out/random.json b/packages/turf-nearest-neighbor-analysis/test/out/random.json index dc651e0471..78a0fb25c1 100644 --- a/packages/turf-nearest-neighbor-analysis/test/out/random.json +++ b/packages/turf-nearest-neighbor-analysis/test/out/random.json @@ -1217,10 +1217,10 @@ "units": "kilometers", "arealUnits": "kilometers²", "observedMeanDistance": 1.6516270145942438, - "expectedMeanDistance": 1.5869473002517003, - "nearestNeighborIndex": 1.0407573171032742, + "expectedMeanDistance": 1.5869473002516816, + "nearestNeighborIndex": 1.0407573171032865, "numberOfPoints": 150, - "zScore": 0.9549532272328554 + "zScore": 0.9549532272331418 } }, "geometry": { From 46a2dd93981996750a51015e2104cb294b541fef Mon Sep 17 00:00:00 2001 From: AminoffZ Date: Tue, 14 Nov 2023 23:37:37 +0200 Subject: [PATCH 5/5] update turf-area benchmark --- packages/turf-area/bench.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/turf-area/bench.js b/packages/turf-area/bench.js index 75c9e2995c..5daa8ac15e 100644 --- a/packages/turf-area/bench.js +++ b/packages/turf-area/bench.js @@ -17,7 +17,7 @@ const fixtures = fs.readdirSync(directory).map((filename) => { /** * Benmark Results * - * polygon x 3,240,248 ops/sec ±0.91% (90 runs sampled) + * polygon x 8,510,024 ops/sec ±0.28% (96 runs sampled) */ // Define benchmark