diff --git a/.monorepolint.config.mjs b/.monorepolint.config.mjs index 58617304cd..fcbf980389 100644 --- a/.monorepolint.config.mjs +++ b/.monorepolint.config.mjs @@ -148,6 +148,7 @@ export default { }, }, includePackages: [...TS_PACKAGES, ...JS_PACKAGES], + excludePackages: ["@turf/internal"], }), packageEntry({ @@ -157,6 +158,7 @@ export default { }, }, includePackages: [...TS_PACKAGES, ...JS_PACKAGES], + excludePackages: ["@turf/internal"], }), packageEntry({ @@ -165,6 +167,7 @@ export default { funding: "https://opencollective.com/turf", }, }, + excludePackages: ["@turf/internal"], }), packageScript({ @@ -174,7 +177,7 @@ export default { test: "pnpm run /test:.*/", }, }, - excludePackages: [MAIN_PACKAGE], + excludePackages: [MAIN_PACKAGE, "@turf/internal"], }), packageScript({ @@ -184,6 +187,7 @@ export default { }, }, includePackages: [...TS_PACKAGES, ...JS_PACKAGES], + excludePackages: ["@turf/internal"], }), packageScript({ @@ -226,6 +230,7 @@ export default { }, }, includePackages: [...TS_PACKAGES, ...JS_PACKAGES], + excludePackages: ["@turf/internal"], }), requireDependency({ @@ -240,6 +245,7 @@ export default { }, }, includePackages: TS_PACKAGES, + excludePackages: ["@turf/internal"], }), requireDependency({ diff --git a/nx.json b/nx.json index e6ced2dd5d..c5a0b0452c 100644 --- a/nx.json +++ b/nx.json @@ -6,7 +6,11 @@ "{projectRoot}/package.json", "{projectRoot}/tsconfig.json" ], - "sources": ["{projectRoot}/index.{js,ts}", "{projectRoot}/lib/**"] + "sources": [ + "{projectRoot}/index.{js,ts}", + "{projectRoot}/lib/**", + "{projectRoot}/src/**" + ] }, "targetDefaults": { "build": { diff --git a/packages/internal/LICENSE b/packages/internal/LICENSE new file mode 100644 index 0000000000..96ce51b76f --- /dev/null +++ b/packages/internal/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2017 TurfJS + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/internal/README.md b/packages/internal/README.md new file mode 100644 index 0000000000..d1752bfea9 --- /dev/null +++ b/packages/internal/README.md @@ -0,0 +1,23 @@ +# @turf/internal + + + + + +--- + +This module is part of the [Turfjs project](https://turfjs.org/), an open source module collection dedicated to geographic algorithms. It is maintained in the [Turfjs/turf](https://github.com/Turfjs/turf) repository, where you can create PRs and issues. + +### Installation + +Install this single module individually: + +```sh +$ npm install @turf/internal +``` + +Or install the all-encompassing @turf/turf module that includes all modules as functions: + +```sh +$ npm install @turf/turf +``` diff --git a/packages/internal/package.json b/packages/internal/package.json new file mode 100644 index 0000000000..989713b88c --- /dev/null +++ b/packages/internal/package.json @@ -0,0 +1,59 @@ +{ + "name": "@turf/internal", + "version": "7.3.1", + "description": "Common functionality used across multiple Turf packages.", + "author": "Turf Authors", + "contributors": [ + "James Beard <@smallsaucepan>" + ], + "license": "MIT", + "bugs": { + "url": "https://github.com/Turfjs/turf/issues" + }, + "homepage": "https://github.com/Turfjs/turf", + "repository": { + "type": "git", + "url": "git://github.com/Turfjs/turf.git" + }, + "funding": "https://opencollective.com/turf", + "publishConfig": { + "access": "public" + }, + "type": "module", + "exports": { + "./package.json": "./package.json", + "./clipper2": { + "import": { + "types": "./dist/esm/clipper2.d.ts", + "default": "./dist/esm/clipper2.js" + }, + "require": { + "types": "./dist/cjs/clipper2.d.cts", + "default": "./dist/cjs/clipper2.cjs" + } + } + }, + "sideEffects": false, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "test": "pnpm run /test:.*/", + "test:tape": "tsx test.ts" + }, + "devDependencies": { + "@babel/core": "^7.26.10", + "@babel/types": "^7.26.10", + "@types/babel__core": "^7.20.5", + "@types/tape": "^5.8.1", + "tape": "^5.9.0", + "tsup": "^8.4.0" + }, + "dependencies": { + "@types/geojson": "^7946.0.10", + "clipper2-ts": "^2.0.1", + "jsbi": "^4.3.2", + "tslib": "^2.8.1" + } +} diff --git a/packages/internal/src/clipper2/index.ts b/packages/internal/src/clipper2/index.ts new file mode 100644 index 0000000000..1e9cc5360d --- /dev/null +++ b/packages/internal/src/clipper2/index.ts @@ -0,0 +1,188 @@ +import { PolyPathD, PathD, PathsD, PolyTreeD, areaD } from "clipper2-ts"; +import { Polygon, MultiPolygon, Position } from "geojson"; + +/* + * Clipper2 scaling factor used when converting between decimal and integer + * values for internal clipper2 calculations. + * For Turf's purposes defaults to 8 decimal places retained, which is approx + * 1mm if using decimal degrees at the equator. + */ +const TURF_CLIPPER2_SCALE_FACTOR = 8; + +/** + * Converts a multipolygon to a flattened array of clipper2 paths. + */ +function multiPolygonToPaths(coords: Position[][][]): PathsD { + const paths: PathsD = []; + + for (const polygon of coords) { + for (const ring of polygonToPaths(polygon)) { + paths.push(ring); + } + } + + return paths; +} + +/** + * Converts a polygon to a flattened array of clipper2 paths. + */ +function polygonToPaths(coords: Position[][]): PathsD { + const paths: PathsD = []; + + for (const [idx, ring] of coords.entries()) { + // Defensive checking against incorrectly wound Geojson polygons. + const checkedRing = + idx === 0 + ? enforceOuterRing(ringToPath(ring)) + : enforceInnerRing(ringToPath(ring)); + + paths.push(checkedRing); + } + + return paths; +} + +/** + * Make sure this ring is wound as an outer ring, according to clipper2 + * expectations. That is, clockwise. + */ +function enforceOuterRing(path: PathD): PathD { + if (areaD(path) < 0) { + return path.reverse(); + } + + return path; +} + +/** + * Make sure this ring is wound as an inner ring, according to clipper2 + * expectations. That is, counter clockwise. + */ +function enforceInnerRing(path: PathD): PathD { + if (areaD(path) > 0) { + // Leave original array untouched. + return [...path].reverse(); + } + + return path; +} + +/** + * Converts a ring to a clipper2 path. + */ +function ringToPath(ring: Position[]): PathD { + return ring.map(([x, y]) => ({ x, y })); +} + +/** + * Construct the output Geojson based on a clipper2 tree. The tree is useful + * for propertly handing holes. + * + * @param polyTree hierarchy of outer and inner contours found by clipper2 + */ +function polyTreeToGeoJSON(polyTree: PolyTreeD): Polygon | MultiPolygon | null { + const polygons: Position[][][] = []; + + // Process each top-level polygon (initally all outer contours) + for (let i = 0; i < polyTree.count; i++) { + const child = polyTree.child(i); + processPolyPath(child, polygons); + } + + if (polygons.length === 0) { + return null; + } + + // If exactly 1 polygon return as Geojson Polygon + if (polygons.length === 1) { + return { + type: "Polygon", + coordinates: polygons[0], + }; + } + + // If anything else return as MultiPolygon + return { + type: "MultiPolygon", + coordinates: polygons, + }; +} + +/** + * Processes a polyPath. Depending on whether the path denotes an outer ring or a hole, will add a polygon to the list of polygons. + * Recurses to children of this polyPath in turn. + * + * @param polyPath outer or inner contour of a polygon to process + * @param polygons array of completed polygons that this function may add to + */ +function processPolyPath(polyPath: PolyPathD, polygons: Position[][][]) { + // Don't look closely at holes during recursion ... + if (!polyPath.isHole) { + const rings: Position[][] = []; + // Add the outer ring. + const outerRing = pathToCoordinates(polyPath.poly); + if (outerRing.length > 0) { + rings.push(outerRing); + } + + // ... instead add holes here. + // Add any holes (direct children are the holes). Do this now rather than + // during recursion given we already have the outer ring handy. + for (let i = 0; i < polyPath.count; i++) { + const child = polyPath.child(i); + + const holeRing = pathToCoordinates(child.poly); + if (holeRing.length > 0) { + rings.push(holeRing); + } + } + polygons.push(rings); + } + + // Now recurse into each child to handle nested levels. + for (let i = 0; i < polyPath.count; i++) { + processPolyPath(polyPath.child(i), polygons); + } +} + +/** + * Converts a clipper2 path to an array of Geojson Positions. + * Automatically closes the path unless overridden e.g. for a lineString. + * + * @param path clipper2 path to convert to Positions + * @param [closeIt=true] close the path by making sure first and last positions are equal + */ +function pathToCoordinates( + path: PathD | null, + closeIt: boolean = true +): Position[] { + const coords: Position[] = []; + + if (!path || typeof path.length !== "number") { + return coords; + } + + for (let i = 0; i < path.length; i++) { + const pt = path[i]; + coords.push([pt.x, pt.y]); + } + + // GeoJSON requires the first and last coordinates to be identical (closed ring) + if (coords.length > 0 && closeIt) { + const first = coords[0]; + const last = coords[coords.length - 1]; + if (first[0] !== last[0] || first[1] !== last[1]) { + coords.push([first[0], first[1]]); + } + } + + return coords; +} + +export { + multiPolygonToPaths, + polygonToPaths, + polyTreeToGeoJSON, + TURF_CLIPPER2_SCALE_FACTOR, +}; diff --git a/packages/internal/test.ts b/packages/internal/test.ts new file mode 100644 index 0000000000..54b7b3fd2e --- /dev/null +++ b/packages/internal/test.ts @@ -0,0 +1,16 @@ +import test from "tape"; +import { FillRule, ClipType, PolyTreeD, ClipperD } from "clipper2-ts"; +import { + TURF_CLIPPER2_SCALE_FACTOR, + multiPolygonToPaths, + polygonToPaths, + polyTreeToGeoJSON, +} from "./src/clipper2/index.js"; + +test("clipper2", (t) => { + const clipper = new ClipperD(TURF_CLIPPER2_SCALE_FACTOR); + + clipper.clear(); + + t.end(); +}); diff --git a/packages/internal/tsconfig.json b/packages/internal/tsconfig.json new file mode 100644 index 0000000000..563bf86442 --- /dev/null +++ b/packages/internal/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.shared.json" +} diff --git a/packages/internal/tsup.config.ts b/packages/internal/tsup.config.ts new file mode 100644 index 0000000000..0634185024 --- /dev/null +++ b/packages/internal/tsup.config.ts @@ -0,0 +1,30 @@ +import { defineConfig, type Options } from "tsup"; + +const baseOptions: Options = { + clean: true, + dts: true, + entry: { + clipper2: "src/clipper2/index.ts", + }, + minify: false, + skipNodeModulesBundle: true, + sourcemap: true, + target: "es2017", + tsconfig: "./tsconfig.json", + // treeshake: true, causes "chunk.default" warning, breaks CJS exports? + cjsInterop: true, + splitting: true, +}; + +export default [ + defineConfig({ + ...baseOptions, + outDir: "dist/cjs", + format: "cjs", + }), + defineConfig({ + ...baseOptions, + outDir: "dist/esm", + format: "esm", + }), +]; diff --git a/packages/turf-difference/index.ts b/packages/turf-difference/index.ts index e0d2af1950..2e8169737d 100644 --- a/packages/turf-difference/index.ts +++ b/packages/turf-difference/index.ts @@ -1,7 +1,13 @@ import { Polygon, MultiPolygon, Feature, FeatureCollection } from "geojson"; -import * as polyclip from "polyclip-ts"; -import { polygon, multiPolygon } from "@turf/helpers"; +import { feature } from "@turf/helpers"; import { geomEach } from "@turf/meta"; +import { ClipperD, ClipType, FillRule, PolyTreeD } from "clipper2-ts"; +import { + TURF_CLIPPER2_SCALE_FACTOR, + multiPolygonToPaths, + polygonToPaths, + polyTreeToGeoJSON, +} from "@turf/internal/clipper2"; /** * Finds the difference between multiple {@link Polygon|polygons} by clipping the subsequent polygon from the first. @@ -39,22 +45,35 @@ import { geomEach } from "@turf/meta"; function difference( features: FeatureCollection ): Feature | null { - const geoms: Array = []; + if (features.features.length < 2) { + throw new Error("Must have at least 2 features"); + } - geomEach(features, (geom) => { - geoms.push(geom.coordinates as polyclip.Geom); - }); + const clipper = new ClipperD(TURF_CLIPPER2_SCALE_FACTOR); - if (geoms.length < 2) { - throw new Error("Must have at least two features"); - } + geomEach(features, (geom, idx) => { + if (geom.type === "MultiPolygon") { + if (idx === 0) { + clipper.addSubjectPaths(multiPolygonToPaths(geom.coordinates)); + } else { + clipper.addClipPaths(multiPolygonToPaths(geom.coordinates)); + } + } else { + if (idx === 0) { + clipper.addSubjectPaths(polygonToPaths(geom.coordinates)); + } else { + clipper.addClipPaths(polygonToPaths(geom.coordinates)); + } + } + }); - const properties = features.features[0].properties || {}; + const tree = new PolyTreeD(); + clipper.execute(ClipType.Difference, FillRule.EvenOdd, tree); - const differenced = polyclip.difference(geoms[0], ...geoms.slice(1)); - if (differenced.length === 0) return null; - if (differenced.length === 1) return polygon(differenced[0], properties); - return multiPolygon(differenced, properties); + // Return the result as Polygon, MultiPolygon, or null as appropriate + const geom = polyTreeToGeoJSON(tree); + if (geom === null) return null; + return feature(geom); } export { difference }; diff --git a/packages/turf-difference/package.json b/packages/turf-difference/package.json index ad2d1db2e4..b67d51421a 100644 --- a/packages/turf-difference/package.json +++ b/packages/turf-difference/package.json @@ -62,9 +62,10 @@ }, "dependencies": { "@turf/helpers": "workspace:*", + "@turf/internal": "workspace:*", "@turf/meta": "workspace:*", "@types/geojson": "^7946.0.10", - "polyclip-ts": "^0.16.8", + "clipper2-ts": "^2.0.1", "tslib": "^2.8.1" } } diff --git a/packages/turf-difference/test.ts b/packages/turf-difference/test.ts index 6b1a15b1d8..699b776440 100644 --- a/packages/turf-difference/test.ts +++ b/packages/turf-difference/test.ts @@ -17,7 +17,8 @@ const directories = { test("turf-difference", (t) => { glob.sync(directories.in + "*.geojson").forEach((filepath) => { const { name, base } = path.parse(filepath); - const [polygon1, polygon2] = loadJsonFileSync(filepath).features; + const [polygon1, polygon2, ...polygon3] = + loadJsonFileSync(filepath).features; if (name.includes("skip")) return t.skip(name); @@ -32,7 +33,7 @@ test("turf-difference", (t) => { fill: "#00F", }); - const results = featureCollection([polygon1, polygon2]); + const results = featureCollection([polygon1, polygon2, ...polygon3]); const result = difference(results); if (result) { diff --git a/packages/turf-difference/test/in/islands-multiple.geojson b/packages/turf-difference/test/in/islands-multiple.geojson new file mode 100644 index 0000000000..8aa79d1fb8 --- /dev/null +++ b/packages/turf-difference/test/in/islands-multiple.geojson @@ -0,0 +1,146 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [100.341829, 21.707513], + [99.946218, 18.265736], + [104.497972, 18.103249], + [104.507178, 21.699765], + [100.341829, 21.707513] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [103.987606, 21.227485], + [100.921818, 21.235346], + [100.574542, 18.952871], + [104.123395, 18.527677], + [103.987606, 21.227485] + ], + [ + [101.495625, 19.485559], + [101.602049, 20.579957], + [103.014364, 20.515371], + [103.490307, 19.967501], + [102.75797, 19.36418], + [101.495625, 19.485559] + ] + ], + [ + [ + [103.20384, 19.959388], + [102.697848, 20.315749], + [101.792497, 20.382879], + [101.679461, 19.748293], + [102.631796, 19.6454], + [103.20384, 19.959388] + ], + [ + [101.857201, 19.836747], + [101.887131, 20.172541], + [102.608327, 20.146421], + [102.519141, 19.806948], + [101.857201, 19.836747] + ], + [ + [102.710175, 20.145995], + [103.016792, 19.96959], + [102.716091, 19.807209], + [102.710175, 20.145995] + ] + ], + [ + [ + [102.467324, 19.906336], + [102.483859, 20.007542], + [102.433872, 20.091891], + [102.30271, 20.114574], + [102.198807, 20.067657], + [102.154763, 20.120171], + [102.022812, 20.12187], + [101.932984, 20.056346], + [101.931027, 19.956909], + [101.982923, 19.894882], + [102.104859, 19.885437], + [102.160847, 19.930535], + [102.204835, 19.855339], + [102.380026, 19.846195], + [102.467324, 19.906336] + ], + [ + [102.016567, 19.965037], + [102.007976, 20.016831], + [102.025106, 20.050394], + [102.081247, 20.059202], + [102.12169, 20.041848], + [102.145916, 20.014495], + [102.130554, 19.961962], + [102.070892, 19.951353], + [102.016567, 19.965037] + ], + [ + [102.247885, 19.88569], + [102.218625, 19.938108], + [102.233982, 20.014125], + [102.299533, 20.055184], + [102.375656, 20.044778], + [102.423278, 19.993367], + [102.405766, 19.911304], + [102.346589, 19.879453], + [102.247885, 19.88569] + ] + ], + [ + [ + [102.113123, 20.010395], + [102.104508, 20.025803], + [102.084663, 20.009513], + [102.096753, 19.999083], + [102.113123, 20.010395] + ] + ], + [ + [ + [102.068298, 20.00723], + [102.054491, 20.025105], + [102.039792, 20.010625], + [102.051026, 19.998426], + [102.068298, 20.00723] + ] + ], + [ + [ + [102.325155, 19.913375], + [102.329922, 19.94424], + [102.366693, 19.950325], + [102.362254, 19.981083], + [102.323385, 19.979151], + [102.323375, 20.014048], + [102.297362, 20.010017], + [102.292975, 19.975096], + [102.257956, 19.977134], + [102.255539, 19.952425], + [102.297063, 19.948326], + [102.294479, 19.913356], + [102.325155, 19.913375] + ] + ] + ] + } + } + ] +} diff --git a/packages/turf-difference/test/in/islands.geojson b/packages/turf-difference/test/in/islands.geojson new file mode 100644 index 0000000000..b8b66a4484 --- /dev/null +++ b/packages/turf-difference/test/in/islands.geojson @@ -0,0 +1,67 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-56.262408, 3.517085], + [-56.262408, -4.571427], + [-46.193645, -4.571427], + [-46.193645, 3.517085], + [-56.262408, 3.517085] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-51.241521, 2.506449], + [-54.474222, -0.594385], + [-51.263364, -3.802459], + [-47.768553, -0.616227], + [-51.241521, 2.506449] + ], + [ + [-51.307049, 1.371305], + [-48.926209, -0.703591], + [-51.219679, -2.73393], + [-53.27288, -0.528861], + [-51.307049, 1.371305] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-51.962326, 0.257464], + [-51.962326, -1.533443], + [-50.324133, -1.533443], + [-50.324133, 0.257464], + [-51.962326, 0.257464] + ], + [ + [-51.711136, 0.04996], + [-50.55348, 0.04996], + [-50.55348, -1.249574], + [-51.711136, -1.249574], + [-51.711136, 0.04996] + ] + ], + "type": "Polygon" + } + } + ] +} diff --git a/packages/turf-difference/test/out/clip-polygons.geojson b/packages/turf-difference/test/out/clip-polygons.geojson index a6bedea0b0..7af18c6097 100644 --- a/packages/turf-difference/test/out/clip-polygons.geojson +++ b/packages/turf-difference/test/out/clip-polygons.geojson @@ -47,21 +47,18 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "Polygon", "coordinates": [ [ - [127.705078125, -34.52466147177172], - [139.5703125, -34.52466147177172], - [139.5703125, -29.075375179558346], - [133.154296875, -29.075375179558346], - [133.154296875, -15.28418511407642], - [127.705078125, -15.28418511407642], - [127.705078125, -34.52466147177172] + [139.5703125, -29.07537518], + [133.15429688, -29.07537518], + [133.15429688, -15.284185110000001], + [127.70507813, -15.284185110000001], + [127.70507813, -34.52466147], + [139.5703125, -34.52466147], + [139.5703125, -29.07537518] ] ] } diff --git a/packages/turf-difference/test/out/create-hole.geojson b/packages/turf-difference/test/out/create-hole.geojson index e74d33a70f..5d8a5eac33 100644 --- a/packages/turf-difference/test/out/create-hole.geojson +++ b/packages/turf-difference/test/out/create-hole.geojson @@ -55,11 +55,11 @@ "type": "Polygon", "coordinates": [ [ - [121, -31], - [144, -31], [144, -15], [121, -15], - [121, -31] + [121, -31], + [144, -31], + [144, -15] ], [ [126, -28], diff --git a/packages/turf-difference/test/out/islands-multiple.geojson b/packages/turf-difference/test/out/islands-multiple.geojson new file mode 100644 index 0000000000..37796b5249 --- /dev/null +++ b/packages/turf-difference/test/out/islands-multiple.geojson @@ -0,0 +1,278 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, + "geometry": { + "coordinates": [ + [ + [100.341829, 21.707513], + [99.946218, 18.265736], + [104.497972, 18.103249], + [104.507178, 21.699765], + [100.341829, 21.707513] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [103.987606, 21.227485], + [100.921818, 21.235346], + [100.574542, 18.952871], + [104.123395, 18.527677], + [103.987606, 21.227485] + ], + [ + [101.495625, 19.485559], + [101.602049, 20.579957], + [103.014364, 20.515371], + [103.490307, 19.967501], + [102.75797, 19.36418], + [101.495625, 19.485559] + ] + ], + [ + [ + [103.20384, 19.959388], + [102.697848, 20.315749], + [101.792497, 20.382879], + [101.679461, 19.748293], + [102.631796, 19.6454], + [103.20384, 19.959388] + ], + [ + [101.857201, 19.836747], + [101.887131, 20.172541], + [102.608327, 20.146421], + [102.519141, 19.806948], + [101.857201, 19.836747] + ], + [ + [102.710175, 20.145995], + [103.016792, 19.96959], + [102.716091, 19.807209], + [102.710175, 20.145995] + ] + ], + [ + [ + [102.467324, 19.906336], + [102.483859, 20.007542], + [102.433872, 20.091891], + [102.30271, 20.114574], + [102.198807, 20.067657], + [102.154763, 20.120171], + [102.022812, 20.12187], + [101.932984, 20.056346], + [101.931027, 19.956909], + [101.982923, 19.894882], + [102.104859, 19.885437], + [102.160847, 19.930535], + [102.204835, 19.855339], + [102.380026, 19.846195], + [102.467324, 19.906336] + ], + [ + [102.016567, 19.965037], + [102.007976, 20.016831], + [102.025106, 20.050394], + [102.081247, 20.059202], + [102.12169, 20.041848], + [102.145916, 20.014495], + [102.130554, 19.961962], + [102.070892, 19.951353], + [102.016567, 19.965037] + ], + [ + [102.247885, 19.88569], + [102.218625, 19.938108], + [102.233982, 20.014125], + [102.299533, 20.055184], + [102.375656, 20.044778], + [102.423278, 19.993367], + [102.405766, 19.911304], + [102.346589, 19.879453], + [102.247885, 19.88569] + ] + ], + [ + [ + [102.113123, 20.010395], + [102.104508, 20.025803], + [102.084663, 20.009513], + [102.096753, 19.999083], + [102.113123, 20.010395] + ] + ], + [ + [ + [102.068298, 20.00723], + [102.054491, 20.025105], + [102.039792, 20.010625], + [102.051026, 19.998426], + [102.068298, 20.00723] + ] + ], + [ + [ + [102.325155, 19.913375], + [102.329922, 19.94424], + [102.366693, 19.950325], + [102.362254, 19.981083], + [102.323385, 19.979151], + [102.323375, 20.014048], + [102.297362, 20.010017], + [102.292975, 19.975096], + [102.257956, 19.977134], + [102.255539, 19.952425], + [102.297063, 19.948326], + [102.294479, 19.913356], + [102.325155, 19.913375] + ] + ] + ] + } + }, + { + "type": "Feature", + "properties": { "fill-opacity": 1, "fill": "#0F0" }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [104.507178, 21.699765], + [100.341829, 21.707513], + [99.946218, 18.265736], + [104.497972, 18.103249], + [104.507178, 21.699765] + ], + [ + [100.57454200000001, 18.952871000000002], + [100.921818, 21.235346], + [103.987606, 21.227485], + [104.123395, 18.527677], + [100.57454200000001, 18.952871000000002] + ] + ], + [ + [ + [103.490307, 19.967501000000002], + [103.014364, 20.515371000000002], + [101.60204900000001, 20.579957], + [101.495625, 19.485559000000002], + [102.75797, 19.36418], + [103.490307, 19.967501000000002] + ], + [ + [101.679461, 19.748293], + [101.792497, 20.382879], + [102.69784800000001, 20.315749], + [103.20384, 19.959388], + [102.63179600000001, 19.6454], + [101.679461, 19.748293] + ] + ], + [ + [ + [102.608327, 20.146421], + [101.887131, 20.172541], + [101.857201, 19.836747], + [102.519141, 19.806948000000002], + [102.608327, 20.146421] + ], + [ + [102.204835, 19.855339], + [102.160847, 19.930535], + [102.104859, 19.885437], + [101.982923, 19.894882], + [101.931027, 19.956909], + [101.932984, 20.056346], + [102.022812, 20.12187], + [102.154763, 20.120171], + [102.198807, 20.067657], + [102.30271, 20.114574], + [102.43387200000001, 20.091891], + [102.483859, 20.007542], + [102.467324, 19.906336], + [102.380026, 19.846195], + [102.204835, 19.855339] + ] + ], + [ + [ + [102.130554, 19.961962], + [102.145916, 20.014495], + [102.12169, 20.041848], + [102.081247, 20.059202], + [102.02510600000001, 20.050394], + [102.007976, 20.016831], + [102.01656700000001, 19.965037], + [102.070892, 19.951353], + [102.130554, 19.961962] + ], + [ + [102.084663, 20.009513000000002], + [102.104508, 20.025803], + [102.113123, 20.010395], + [102.096753, 19.999083], + [102.084663, 20.009513000000002] + ], + [ + [102.039792, 20.010625], + [102.054491, 20.025105], + [102.068298, 20.00723], + [102.05102600000001, 19.998426000000002], + [102.039792, 20.010625] + ] + ], + [ + [ + [102.405766, 19.911304], + [102.423278, 19.993367], + [102.375656, 20.044778], + [102.299533, 20.055184], + [102.233982, 20.014125], + [102.218625, 19.938108], + [102.247885, 19.88569], + [102.34658900000001, 19.879453], + [102.405766, 19.911304] + ], + [ + [102.29706300000001, 19.948326], + [102.255539, 19.952425], + [102.25795600000001, 19.977134], + [102.292975, 19.975096], + [102.297362, 20.010017], + [102.323375, 20.014048], + [102.323385, 19.979151], + [102.36225400000001, 19.981083], + [102.366693, 19.950325], + [102.329922, 19.94424], + [102.325155, 19.913375000000002], + [102.294479, 19.913356], + [102.29706300000001, 19.948326] + ] + ], + [ + [ + [103.016792, 19.96959], + [102.710175, 20.145995], + [102.716091, 19.807209], + [103.016792, 19.96959] + ] + ] + ] + } + } + ] +} diff --git a/packages/turf-difference/test/out/islands.geojson b/packages/turf-difference/test/out/islands.geojson new file mode 100644 index 0000000000..20bb6327fc --- /dev/null +++ b/packages/turf-difference/test/out/islands.geojson @@ -0,0 +1,117 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, + "geometry": { + "coordinates": [ + [ + [-56.262408, 3.517085], + [-56.262408, -4.571427], + [-46.193645, -4.571427], + [-46.193645, 3.517085], + [-56.262408, 3.517085] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, + "geometry": { + "coordinates": [ + [ + [-51.241521, 2.506449], + [-54.474222, -0.594385], + [-51.263364, -3.802459], + [-47.768553, -0.616227], + [-51.241521, 2.506449] + ], + [ + [-51.307049, 1.371305], + [-48.926209, -0.703591], + [-51.219679, -2.73393], + [-53.27288, -0.528861], + [-51.307049, 1.371305] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-51.962326, 0.257464], + [-51.962326, -1.533443], + [-50.324133, -1.533443], + [-50.324133, 0.257464], + [-51.962326, 0.257464] + ], + [ + [-51.711136, 0.04996], + [-50.55348, 0.04996], + [-50.55348, -1.249574], + [-51.711136, -1.249574], + [-51.711136, 0.04996] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": { "fill-opacity": 1, "fill": "#0F0" }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-46.193645000000004, 3.5170850000000002], + [-56.262408, 3.5170850000000002], + [-56.262408, -4.571427], + [-46.193645000000004, -4.571427], + [-46.193645000000004, 3.5170850000000002] + ], + [ + [-54.474222000000005, -0.594385], + [-51.241521, 2.506449], + [-47.768553000000004, -0.616227], + [-51.263364, -3.8024590000000003], + [-54.474222000000005, -0.594385] + ] + ], + [ + [ + [-48.926209, -0.703591], + [-51.307049, 1.371305], + [-53.27288, -0.528861], + [-51.219679, -2.73393], + [-48.926209, -0.703591] + ], + [ + [-51.962326000000004, -1.5334430000000001], + [-51.962326000000004, 0.257464], + [-50.324133, 0.257464], + [-50.324133, -1.5334430000000001], + [-51.962326000000004, -1.5334430000000001] + ] + ], + [ + [ + [-50.55348, -1.249574], + [-50.55348, 0.049960000000000004], + [-51.711136, 0.049960000000000004], + [-51.711136, -1.249574], + [-50.55348, -1.249574] + ] + ] + ] + } + } + ] +} diff --git a/packages/turf-difference/test/out/issue-#721-inverse.geojson b/packages/turf-difference/test/out/issue-#721-inverse.geojson index 9bacfc3c01..477c618427 100644 --- a/packages/turf-difference/test/out/issue-#721-inverse.geojson +++ b/packages/turf-difference/test/out/issue-#721-inverse.geojson @@ -92,42 +92,6 @@ ] ] } - }, - { - "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [-0.6462588068806041, 44.80608667910215], - [-0.6462588068796641, 44.80608667910137], - [-0.6461987, 44.8060367], - [-0.6462588068806041, 44.80608667910215] - ] - ], - [ - [ - [-0.6461042, 44.8059451], - [-0.6461041344154723, 44.805944903377586], - [-0.6461041344154722, 44.805944903377586], - [-0.6461042, 44.8059451] - ] - ], - [ - [ - [-0.6460471709105139, 44.80564743856641], - [-0.6460421, 44.8056729], - [-0.6460471709104708, 44.80564743856663], - [-0.6460471709105139, 44.80564743856641] - ] - ] - ] - } } ] } diff --git a/packages/turf-difference/test/out/issue-#721.geojson b/packages/turf-difference/test/out/issue-#721.geojson index 08606ca524..ef5bc2c0ad 100644 --- a/packages/turf-difference/test/out/issue-#721.geojson +++ b/packages/turf-difference/test/out/issue-#721.geojson @@ -95,55 +95,64 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { - "type": "Polygon", + "type": "MultiPolygon", "coordinates": [ [ - [-0.6474134, 44.805326], - [-0.6472295, 44.8050484], - [-0.6469113, 44.8048572], - [-0.6465997, 44.8047375], - [-0.6462847, 44.8042192], - [-0.646075, 44.8042943], - [-0.645829, 44.8043891], - [-0.6460168, 44.8047948], - [-0.6460827, 44.8050017], - [-0.6461218, 44.8051741], - [-0.6461073, 44.8053383], - [-0.6460848, 44.8054585], - [-0.6460471709104708, 44.80564743856663], - [-0.6460422277450562, 44.805672561504906], - [-0.6460542976856232, 44.80579530680288], - [-0.646069093721612, 44.80583985137739], - [-0.6460542, 44.8057952], - [-0.6461041344154723, 44.805944903377586], - [-0.6461991369724274, 44.80603699057963], - [-0.6462588068796641, 44.80608667910137], - [-0.6463809, 44.8061882], - [-0.646437, 44.806159], - [-0.64649, 44.80611], - [-0.64662, 44.806065], - [-0.6466971, 44.8060413], - [-0.6467005, 44.8059967], - [-0.6466831, 44.8059719], - [-0.6466376, 44.8059546], - [-0.6465922, 44.8059124], - [-0.6465119, 44.8057959], - [-0.6464734, 44.8056645], - [-0.6465049, 44.8055554], - [-0.6471907, 44.8053946], - [-0.6474134, 44.805326] + [ + [-0.64610413, 44.8059449], + [-0.64619914, 44.80603699], + [-0.64625881, 44.80608668], + [-0.6463809, 44.8061882], + [-0.646437, 44.806159], + [-0.64649, 44.806110000000004], + [-0.64662, 44.806065000000004], + [-0.6466971, 44.806041300000004], + [-0.6467005, 44.8059967], + [-0.6466831000000001, 44.8059719], + [-0.6466376, 44.8059546], + [-0.6465922000000001, 44.805912400000004], + [-0.6465119, 44.8057959], + [-0.6464734, 44.8056645], + [-0.6465049, 44.8055554], + [-0.6471907, 44.8053946], + [-0.6474134, 44.805326], + [-0.6472295, 44.805048400000004], + [-0.6469113, 44.8048572], + [-0.6465997, 44.8047375], + [-0.6462847, 44.8042192], + [-0.6460750000000001, 44.8042943], + [-0.645829, 44.8043891], + [-0.6460168000000001, 44.8047948], + [-0.6460827, 44.8050017], + [-0.6461218, 44.8051741], + [-0.6461158300000001, 44.8052416], + [-0.64610794, 44.805338580000004], + [-0.6460936700000001, 44.80541109], + [-0.6460848, 44.8054585], + [-0.64604712, 44.80564768], + [-0.64604223, 44.80567256], + [-0.6460543, 44.80579531], + [-0.64606909, 44.80583985], + [-0.64610413, 44.8059449] + ] ], [ - [-0.6461073, 44.8053383], - [-0.6461158838109077, 44.80524109574131], - [-0.646107941865921, 44.80533857879061], - [-0.646093673696575, 44.80541109474097], - [-0.6461073, 44.8053383] + [ + [-0.6461073, 44.8053383], + [-0.64611588, 44.8052411], + [-0.6461158300000001, 44.8052416], + [-0.6461073, 44.8053383] + ] + ], + [ + [ + [-0.6460421000000001, 44.8056729], + [-0.64604717, 44.80564744], + [-0.64604712, 44.80564768], + [-0.6460421000000001, 44.8056729] + ] ] ] } diff --git a/packages/turf-difference/test/out/multi-polygon-input.geojson b/packages/turf-difference/test/out/multi-polygon-input.geojson index db250d9044..55f90acaa8 100644 --- a/packages/turf-difference/test/out/multi-polygon-input.geojson +++ b/packages/turf-difference/test/out/multi-polygon-input.geojson @@ -58,37 +58,34 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ - [119.53125, -39.57182223734373], - [134.560546875, -39.57182223734373], - [134.560546875, -28.38173504322308], - [131.8359375, -28.38173504322308], - [131.8359375, -35.81781315869662], - [126.298828125, -35.81781315869662], - [126.298828125, -28.38173504322308], - [119.53125, -28.38173504322308], - [119.53125, -39.57182223734373] + [136.14257813, -13.06877673], + [123.13476563, -13.06877673], + [123.13476563, -25.56226501], + [126.29882813, -25.56226501], + [126.29882813, -18.39623014], + [131.8359375, -18.39623014], + [131.8359375, -25.56226501], + [136.14257813, -25.56226501], + [136.14257813, -13.06877673] ] ], [ [ - [123.134765625, -25.562265014427492], - [126.298828125, -25.562265014427492], - [126.298828125, -18.396230138028812], - [131.8359375, -18.396230138028812], - [131.8359375, -25.562265014427492], - [136.142578125, -25.562265014427492], - [136.142578125, -13.068776734357694], - [123.134765625, -13.068776734357694], - [123.134765625, -25.562265014427492] + [134.56054688, -28.381735040000002], + [131.8359375, -28.381735040000002], + [131.8359375, -35.81781316], + [126.29882813, -35.81781316], + [126.29882813, -28.381735040000002], + [119.53125, -28.381735040000002], + [119.53125, -39.57182224], + [134.56054688, -39.57182224], + [134.56054688, -28.381735040000002] ] ] ] diff --git a/packages/turf-difference/test/out/multi-polygon-target.geojson b/packages/turf-difference/test/out/multi-polygon-target.geojson index 6d39aedaab..4a6f0b2acb 100644 --- a/packages/turf-difference/test/out/multi-polygon-target.geojson +++ b/packages/turf-difference/test/out/multi-polygon-target.geojson @@ -65,45 +65,42 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ - [127.66113281249999, -30.713503990354965], - [128.8916015625, -30.713503990354965], - [128.8916015625, -20.2209657795223], - [127.66113281249999, -20.2209657795223], - [127.66113281249999, -30.713503990354965] + [128.89160156, -20.22096578], + [127.66113281, -20.22096578], + [127.66113281, -30.71350399], + [128.89160156, -30.71350399], + [128.89160156, -20.22096578] ] ], [ [ - [130.6494140625, -30.713503990354965], - [136.23046875, -30.713503990354965], - [136.23046875, -20.2209657795223], - [130.6494140625, -20.2209657795223], - [130.6494140625, -30.713503990354965] + [136.23046875, -20.22096578], + [130.64941406, -20.22096578], + [130.64941406, -30.71350399], + [136.23046875, -30.71350399], + [136.23046875, -20.22096578] ], [ - [132.38525390625, -27.313213898568247], - [132.38525390625, -24.467150664738988], - [135.1318359375, -24.467150664738988], - [135.1318359375, -27.313213898568247], - [132.38525390625, -27.313213898568247] + [132.38525391, -24.46715066], + [135.13183594, -24.46715066], + [135.13183594, -27.3132139], + [132.38525391, -27.3132139], + [132.38525391, -24.46715066] ] ], [ [ - [138.6474609375, -30.713503990354965], - [140.7568359375, -30.713503990354965], - [140.7568359375, -20.2209657795223], - [138.6474609375, -20.2209657795223], - [138.6474609375, -30.713503990354965] + [140.75683594, -20.22096578], + [138.64746094, -20.22096578], + [138.64746094, -30.71350399], + [140.75683594, -30.71350399], + [140.75683594, -20.22096578] ] ] ] diff --git a/packages/turf-difference/test/out/split-polygon.geojson b/packages/turf-difference/test/out/split-polygon.geojson index 99da2a61ca..fd91c76b09 100644 --- a/packages/turf-difference/test/out/split-polygon.geojson +++ b/packages/turf-difference/test/out/split-polygon.geojson @@ -47,29 +47,26 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ - [122.51953124999999, -29.22889003019423], - [127.705078125, -29.22889003019423], - [127.705078125, -21.53484700204879], - [122.51953124999999, -21.53484700204879], - [122.51953124999999, -29.22889003019423] + [127.70507813, -21.534847], + [122.51953125, -21.534847], + [122.51953125, -29.228890030000002], + [127.70507813, -29.228890030000002], + [127.70507813, -21.534847] ] ], [ [ - [139.5703125, -29.22889003019423], - [144.228515625, -29.22889003019423], - [144.228515625, -21.53484700204879], - [139.5703125, -21.53484700204879], - [139.5703125, -29.22889003019423] + [144.22851563, -21.534847], + [139.5703125, -21.534847], + [139.5703125, -29.228890030000002], + [144.22851563, -29.228890030000002], + [144.22851563, -21.534847] ] ] ] diff --git a/packages/turf-intersect/index.ts b/packages/turf-intersect/index.ts index 55a2d74cd7..a2667490d9 100644 --- a/packages/turf-intersect/index.ts +++ b/packages/turf-intersect/index.ts @@ -5,9 +5,15 @@ import { Polygon, FeatureCollection, } from "geojson"; -import { multiPolygon, polygon } from "@turf/helpers"; +import { feature } from "@turf/helpers"; import { geomEach } from "@turf/meta"; -import * as polyclip from "polyclip-ts"; +import { FillRule, ClipType, PolyTreeD, ClipperD } from "clipper2-ts"; +import { + TURF_CLIPPER2_SCALE_FACTOR, + multiPolygonToPaths, + polygonToPaths, + polyTreeToGeoJSON, +} from "@turf/internal/clipper2"; /** * Takes {@link Polygon|polygon} or {@link MultiPolygon|multi-polygon} geometries and @@ -50,20 +56,35 @@ function intersect

( properties?: P; } = {} ): Feature | null { - const geoms: polyclip.Geom[] = []; + if (features.features.length < 2) { + throw new Error("Must have at least 2 features"); + } + + const clipper = new ClipperD(TURF_CLIPPER2_SCALE_FACTOR); - geomEach(features, (geom) => { - geoms.push(geom.coordinates as polyclip.Geom); + geomEach(features, (geom, idx) => { + if (geom.type === "MultiPolygon") { + if (idx === 0) { + clipper.addSubjectPaths(multiPolygonToPaths(geom.coordinates)); + } else { + clipper.addClipPaths(multiPolygonToPaths(geom.coordinates)); + } + } else { + if (idx === 0) { + clipper.addSubjectPaths(polygonToPaths(geom.coordinates)); + } else { + clipper.addClipPaths(polygonToPaths(geom.coordinates)); + } + } }); - if (geoms.length < 2) { - throw new Error("Must specify at least 2 geometries"); - } - const intersection = polyclip.intersection(geoms[0], ...geoms.slice(1)); - if (intersection.length === 0) return null; - if (intersection.length === 1) - return polygon(intersection[0], options.properties); - return multiPolygon(intersection, options.properties); + const tree = new PolyTreeD(); + clipper.execute(ClipType.Intersection, FillRule.EvenOdd, tree); + + // Return the result as Polygon, MultiPolygon, or null as appropriate + const geom = polyTreeToGeoJSON(tree); + if (geom === null) return null; + return feature(geom, options.properties); } export { intersect }; diff --git a/packages/turf-intersect/package.json b/packages/turf-intersect/package.json index c1993216a1..f0e8aae04a 100644 --- a/packages/turf-intersect/package.json +++ b/packages/turf-intersect/package.json @@ -64,9 +64,10 @@ }, "dependencies": { "@turf/helpers": "workspace:*", + "@turf/internal": "workspace:*", "@turf/meta": "workspace:*", "@types/geojson": "^7946.0.10", - "polyclip-ts": "^0.16.8", + "clipper2-ts": "^2.0.1", "tslib": "^2.8.1" } } diff --git a/packages/turf-intersect/test.ts b/packages/turf-intersect/test.ts index a90665e4fb..a570780110 100644 --- a/packages/turf-intersect/test.ts +++ b/packages/turf-intersect/test.ts @@ -51,7 +51,12 @@ test("intersect", (t) => { const fc = featureCollection([polygon1, polygon2]); const result = intersect(fc); - if (result) { + if ( + result && + (result.geometry.type === "Polygon" || + (result.geometry.type === "MultiPolygon" && + result.geometry.coordinates.length > 0)) + ) { // Green Polygon result.properties = { "fill-opacity": 1, fill: "#0F0" }; fc.features.push(result); diff --git a/packages/turf-intersect/test/in/Intersect3.geojson b/packages/turf-intersect/test/in/Intersect3.geojson new file mode 100644 index 0000000000..0fa4d55ae0 --- /dev/null +++ b/packages/turf-intersect/test/in/Intersect3.geojson @@ -0,0 +1,91 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + [-79.885712, 32.88766], + [-80.097885, 32.927437], + [-80.153503, 32.82825], + [-80.003128, 32.694288], + [-79.893951, 32.75552], + [-79.885712, 32.88766] + ], + [ + [-80.033715, 32.875508], + [-79.941087, 32.866098], + [-79.916897, 32.783297], + [-80.01425, 32.754522], + [-80.079736, 32.836853], + [-80.033715, 32.875508] + ] + ], + [ + [ + [-80.046825, 32.846002], + [-80.012242, 32.803534], + [-79.965252, 32.807258], + [-79.964808, 32.835201], + [-80.009581, 32.857916], + [-80.046825, 32.846002] + ], + [ + [-80.002268, 32.845442], + [-79.999388, 32.836876], + [-79.984315, 32.8352], + [-79.997836, 32.829426], + [-79.995398, 32.815456], + [-80.004708, 32.82626], + [-80.017562, 32.820299], + [-80.011136, 32.831103], + [-80.020224, 32.838552], + [-80.00914, 32.837435], + [-80.002268, 32.845442] + ] + ], + [ + [ + [-79.936652, 32.964886], + [-80.041397, 32.98246], + [-80.079302, 32.946468], + [-79.963587, 32.919675], + [-79.936652, 32.964886] + ] + ] + ], + "type": "MultiPolygon" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-79.921417, 32.953944], + [-79.994467, 32.83401], + [-79.973602, 32.760717], + [-79.930344, 32.764759], + [-79.937897, 32.741082], + [-79.805374, 32.723176], + [-79.817734, 32.923402], + [-79.921417, 32.953944] + ], + [ + [-79.902742, 32.913654], + [-79.841373, 32.895333], + [-79.837838, 32.793218], + [-79.884445, 32.75204], + [-79.946398, 32.814046], + [-79.902742, 32.913654] + ] + ], + "type": "Polygon" + } + } + ] +} diff --git a/packages/turf-intersect/test/out/Intersect1.geojson b/packages/turf-intersect/test/out/Intersect1.geojson index 32a2a3f190..c5a89dc3de 100644 --- a/packages/turf-intersect/test/out/Intersect1.geojson +++ b/packages/turf-intersect/test/out/Intersect1.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -23,10 +20,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -45,23 +39,20 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "Polygon", "coordinates": [ [ - [-79.97428894042969, 32.83690450361482], - [-79.97360229492188, 32.76071688548088], - [-79.93034362792969, 32.76475877693074], - [-79.93789672851562, 32.74108223150125], - [-79.92322780260464, 32.73910022106017], - [-79.89395141601562, 32.75551989829049], - [-79.88571166992188, 32.887659962078956], - [-79.94623496447946, 32.89900638172028], - [-79.97428894042969, 32.83690450361482] + [-79.89395142000001, 32.7555199], + [-79.88571167, 32.88765996], + [-79.94623496, 32.89900637], + [-79.97428894000001, 32.8369045], + [-79.97360229, 32.76071689], + [-79.93034363, 32.76475878], + [-79.93789673, 32.74108223], + [-79.9232278, 32.73910022], + [-79.89395142000001, 32.7555199] ] ] } diff --git a/packages/turf-intersect/test/out/Intersect2.geojson b/packages/turf-intersect/test/out/Intersect2.geojson index 8755e4c990..b31e1b33cc 100644 --- a/packages/turf-intersect/test/out/Intersect2.geojson +++ b/packages/turf-intersect/test/out/Intersect2.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -26,10 +23,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -46,21 +40,18 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "Polygon", "coordinates": [ [ - [-80.068359375, 32.88189375925038], - [-80.01686096191406, 32.87266705436184], - [-80.0066252126598, 32.84617770697059], - [-79.99351501464844, 32.84440429734253], - [-79.98184204101562, 32.90495631913751], - [-80.00501604057509, 32.91295307720083], - [-80.068359375, 32.88189375925038] + [-79.98184204, 32.904956320000004], + [-80.00501604, 32.91295307], + [-80.06835937, 32.881893760000004], + [-80.01686096, 32.872667050000004], + [-80.00662521, 32.8461777], + [-79.99351501, 32.8444043], + [-79.98184204, 32.904956320000004] ] ] } diff --git a/packages/turf-intersect/test/out/Intersect3.geojson b/packages/turf-intersect/test/out/Intersect3.geojson new file mode 100644 index 0000000000..a6ec49cc5b --- /dev/null +++ b/packages/turf-intersect/test/out/Intersect3.geojson @@ -0,0 +1,136 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, + "geometry": { + "coordinates": [ + [ + [ + [-79.885712, 32.88766], + [-80.097885, 32.927437], + [-80.153503, 32.82825], + [-80.003128, 32.694288], + [-79.893951, 32.75552], + [-79.885712, 32.88766] + ], + [ + [-80.033715, 32.875508], + [-79.941087, 32.866098], + [-79.916897, 32.783297], + [-80.01425, 32.754522], + [-80.079736, 32.836853], + [-80.033715, 32.875508] + ] + ], + [ + [ + [-80.046825, 32.846002], + [-80.012242, 32.803534], + [-79.965252, 32.807258], + [-79.964808, 32.835201], + [-80.009581, 32.857916], + [-80.046825, 32.846002] + ], + [ + [-80.002268, 32.845442], + [-79.999388, 32.836876], + [-79.984315, 32.8352], + [-79.997836, 32.829426], + [-79.995398, 32.815456], + [-80.004708, 32.82626], + [-80.017562, 32.820299], + [-80.011136, 32.831103], + [-80.020224, 32.838552], + [-80.00914, 32.837435], + [-80.002268, 32.845442] + ] + ], + [ + [ + [-79.936652, 32.964886], + [-80.041397, 32.98246], + [-80.079302, 32.946468], + [-79.963587, 32.919675], + [-79.936652, 32.964886] + ] + ] + ], + "type": "MultiPolygon" + } + }, + { + "type": "Feature", + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, + "geometry": { + "coordinates": [ + [ + [-79.921417, 32.953944], + [-79.994467, 32.83401], + [-79.973602, 32.760717], + [-79.930344, 32.764759], + [-79.937897, 32.741082], + [-79.805374, 32.723176], + [-79.817734, 32.923402], + [-79.921417, 32.953944] + ], + [ + [-79.902742, 32.913654], + [-79.841373, 32.895333], + [-79.837838, 32.793218], + [-79.884445, 32.75204], + [-79.946398, 32.814046], + [-79.902742, 32.913654] + ] + ], + "type": "Polygon" + } + }, + { + "type": "Feature", + "properties": { "fill-opacity": 1, "fill": "#0F0" }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-79.91197654, 32.89258392], + [-79.95399275, 32.90046089], + [-79.97295104, 32.86933504], + [-79.941087, 32.866098], + [-79.93408666, 32.84213624], + [-79.91197654, 32.89258392] + ] + ], + [ + [ + [-79.965252, 32.807258], + [-79.964808, 32.835201], + [-79.98691138, 32.84641486], + [-79.99314422, 32.83618174], + [-79.984315, 32.8352], + [-79.99366865, 32.83120562], + [-79.9863747, 32.805584], + [-79.965252, 32.807258] + ] + ], + [ + [ + [-79.893951, 32.755520000000004], + [-79.89359686, 32.76119969], + [-79.91740183, 32.78502503], + [-79.916897, 32.783297], + [-79.9751301, 32.76608481], + [-79.973602, 32.760717], + [-79.930344, 32.764759], + [-79.937897, 32.741082], + [-79.92322798000001, 32.73909997], + [-79.893951, 32.755520000000004] + ] + ] + ] + } + } + ] +} diff --git a/packages/turf-intersect/test/out/armenia.geojson b/packages/turf-intersect/test/out/armenia.geojson index 8e9228d9da..78aadf9f12 100644 --- a/packages/turf-intersect/test/out/armenia.geojson +++ b/packages/turf-intersect/test/out/armenia.geojson @@ -4,11 +4,7 @@ { "type": "Feature", "id": "ARM", - "properties": { - "name": "Armenia", - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "name": "Armenia", "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -39,10 +35,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -58,22 +51,19 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "Polygon", "coordinates": [ [ - [45.1318359375, 40.1452892956766], - [45.82712793551521, 40.1452892956766], [45.891907, 40.218476], [45.359175, 40.561504], - [45.560351, 40.81229], + [45.560351000000004, 40.812290000000004], [45.179496, 40.985354], - [45.1318359375, 41.04585112545618], - [45.1318359375, 40.1452892956766] + [45.13183594, 41.04585112], + [45.13183594, 40.1452893], + [45.827127940000004, 40.1452893], + [45.891907, 40.218476] ] ] } diff --git a/packages/turf-intersect/test/out/issue-1004.geojson b/packages/turf-intersect/test/out/issue-1004.geojson index 45a42a10e7..8ed90bbbb2 100644 --- a/packages/turf-intersect/test/out/issue-1004.geojson +++ b/packages/turf-intersect/test/out/issue-1004.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -22,10 +19,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -124,20 +118,17 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "Polygon", "coordinates": [ [ - [-114.757217, 32.619867791666664], - [-114.757213, 32.619753375], - [-114.757213, 32.619926], + [-114.75721300000001, 32.619926], [-114.757215, 32.619925], [-114.757217, 32.619925], - [-114.757217, 32.619867791666664] + [-114.757217, 32.61986779], + [-114.75721300000001, 32.61975337], + [-114.75721300000001, 32.619926] ] ] } diff --git a/packages/turf-intersect/test/out/issue-1394.geojson b/packages/turf-intersect/test/out/issue-1394.geojson index 5bb4706b78..112b634ad1 100644 --- a/packages/turf-intersect/test/out/issue-1394.geojson +++ b/packages/turf-intersect/test/out/issue-1394.geojson @@ -88,24 +88,6 @@ "fill-opacity": 0.5, "fill": "#00F" } - }, - { - "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-85.42358073, 41.76885781], - [-85.42357713028528, 41.76878899545362], - [-85.42357713, 41.768789], - [-85.42358073, 41.76885781] - ] - ] - } } ] } diff --git a/packages/turf-intersect/test/out/issue-412.geojson b/packages/turf-intersect/test/out/issue-412.geojson index aa52f6dec6..afa271f7fb 100644 --- a/packages/turf-intersect/test/out/issue-412.geojson +++ b/packages/turf-intersect/test/out/issue-412.geojson @@ -14,10 +14,7 @@ ] ] }, - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - } + "properties": { "fill-opacity": 0.5, "fill": "#F00" } }, { "type": "Feature", @@ -32,27 +29,20 @@ ] ] }, - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - } + "properties": { "fill-opacity": 0.5, "fill": "#00F" } }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "Polygon", "coordinates": [ [ - [11.076136797048882, 9.856269774244707], - [11.076136797048889, 9.856269774244705], - [11.102599853580049, 9.85386305739084], - [11.167525294018608, 9.85386305739084], - [11.168736108831801, 9.855073034114678], - [11.076136797048882, 9.856269774244707] + [11.168736110000001, 9.85507303], + [11.07613686, 9.85626976], + [11.10259984, 9.85386306], + [11.1675253, 9.85386306], + [11.168736110000001, 9.85507303] ] ] } diff --git a/packages/turf-intersect/test/out/linestring.geojson b/packages/turf-intersect/test/out/linestring.geojson index 4358bc1784..9eadf1e412 100644 --- a/packages/turf-intersect/test/out/linestring.geojson +++ b/packages/turf-intersect/test/out/linestring.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -28,10 +25,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ diff --git a/packages/turf-intersect/test/out/multilinestring.geojson b/packages/turf-intersect/test/out/multilinestring.geojson index 4509b4b880..91006c9489 100644 --- a/packages/turf-intersect/test/out/multilinestring.geojson +++ b/packages/turf-intersect/test/out/multilinestring.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -28,10 +25,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ diff --git a/packages/turf-intersect/test/out/multipoint.geojson b/packages/turf-intersect/test/out/multipoint.geojson index fd54684c1d..02c9487141 100644 --- a/packages/turf-intersect/test/out/multipoint.geojson +++ b/packages/turf-intersect/test/out/multipoint.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -24,10 +21,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ diff --git a/packages/turf-intersect/test/out/multipolygon-input.geojson b/packages/turf-intersect/test/out/multipolygon-input.geojson index 971c29d010..9e4705dcec 100644 --- a/packages/turf-intersect/test/out/multipolygon-input.geojson +++ b/packages/turf-intersect/test/out/multipolygon-input.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -35,10 +32,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "MultiPolygon", "coordinates": [ @@ -65,31 +59,28 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ - [2.3239517211914062, 48.86787657822752], - [2.3499909013050764, 48.85534182435727], - [2.3500442504882812, 48.85613168160397], - [2.3500442504882812, 48.8615527456014], - [2.3273849487304688, 48.87148983809234], - [2.324709348008303, 48.87186313938144], - [2.3239517211914062, 48.86787657822752] + [2.35336532, 48.86714165], + [2.3444407000000003, 48.878043330000004], + [2.33631134, 48.87690924], + [2.35141754, 48.86516646], + [2.35336532, 48.86714165] ] ], [ [ - [2.3363113403320312, 48.87690923865779], - [2.3514175415039062, 48.86516646209463], - [2.353365325175928, 48.86714166070064], - [2.3444407066054644, 48.87804332946407], - [2.3363113403320312, 48.87690923865779] + [2.35004425, 48.856131680000004], + [2.35004425, 48.86155275], + [2.32738495, 48.87148984], + [2.32470934, 48.87186314], + [2.32395172, 48.86787658], + [2.3499909, 48.85534182], + [2.35004425, 48.856131680000004] ] ] ] diff --git a/packages/turf-intersect/test/out/no-overlap.geojson b/packages/turf-intersect/test/out/no-overlap.geojson index 6c6e1918d2..9870084d42 100644 --- a/packages/turf-intersect/test/out/no-overlap.geojson +++ b/packages/turf-intersect/test/out/no-overlap.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -22,10 +19,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ diff --git a/packages/turf-intersect/test/out/output-multipolygon.geojson b/packages/turf-intersect/test/out/output-multipolygon.geojson index 4629f4d3ca..5123cd34e9 100644 --- a/packages/turf-intersect/test/out/output-multipolygon.geojson +++ b/packages/turf-intersect/test/out/output-multipolygon.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -22,10 +19,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -48,29 +42,26 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 1, - "fill": "#0F0" - }, + "properties": { "fill-opacity": 1, "fill": "#0F0" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ - [129.0234375, -27.371767300523032], - [130.2978515625, -27.371767300523032], - [130.2978515625, -22.43134015636061], - [129.0234375, -22.43134015636061], - [129.0234375, -27.371767300523032] + [130.29785156, -22.43134016], + [129.0234375, -22.43134016], + [129.0234375, -27.371767300000002], + [130.29785156, -27.371767300000002], + [130.29785156, -22.43134016] ] ], [ [ - [137.2412109375, -27.371767300523032], - [138.33984375, -27.371767300523032], - [138.33984375, -22.43134015636061], - [137.2412109375, -22.43134015636061], - [137.2412109375, -27.371767300523032] + [138.33984375, -22.43134016], + [137.24121094, -22.43134016], + [137.24121094, -27.371767300000002], + [138.33984375, -27.371767300000002], + [138.33984375, -22.43134016] ] ] ] diff --git a/packages/turf-intersect/test/out/point.geojson b/packages/turf-intersect/test/out/point.geojson index c3f7c7b9b0..74f3632784 100644 --- a/packages/turf-intersect/test/out/point.geojson +++ b/packages/turf-intersect/test/out/point.geojson @@ -3,10 +3,7 @@ "features": [ { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#F00" - }, + "properties": { "fill-opacity": 0.5, "fill": "#F00" }, "geometry": { "type": "Polygon", "coordinates": [ @@ -24,10 +21,7 @@ }, { "type": "Feature", - "properties": { - "fill-opacity": 0.5, - "fill": "#00F" - }, + "properties": { "fill-opacity": 0.5, "fill": "#00F" }, "geometry": { "type": "Polygon", "coordinates": [ diff --git a/packages/turf-union/index.ts b/packages/turf-union/index.ts index 94428494af..6618ae0a3f 100644 --- a/packages/turf-union/index.ts +++ b/packages/turf-union/index.ts @@ -1,5 +1,4 @@ -import * as polyclip from "polyclip-ts"; -import { multiPolygon, polygon } from "@turf/helpers"; +import { feature } from "@turf/helpers"; import { geomEach } from "@turf/meta"; import { FeatureCollection, @@ -8,6 +7,13 @@ import { MultiPolygon, GeoJsonProperties, } from "geojson"; +import { FillRule, ClipType, PolyTreeD, ClipperD } from "clipper2-ts"; +import { + TURF_CLIPPER2_SCALE_FACTOR, + multiPolygonToPaths, + polygonToPaths, + polyTreeToGeoJSON, +} from "@turf/internal/clipper2"; /** * Takes a collection of input polygons and returns a combined polygon. If the @@ -61,19 +67,35 @@ function union

( features: FeatureCollection, options: { properties?: P } = {} ): Feature | null { - const geoms: polyclip.Geom[] = []; - geomEach(features, (geom) => { - geoms.push(geom.coordinates as polyclip.Geom); + if (features.features.length < 2) { + throw new Error("Must have at least 2 features"); + } + + const clipper = new ClipperD(TURF_CLIPPER2_SCALE_FACTOR); + + geomEach(features, (geom, idx) => { + if (geom.type === "MultiPolygon") { + if (idx === 0) { + clipper.addSubjectPaths(multiPolygonToPaths(geom.coordinates)); + } else { + clipper.addClipPaths(multiPolygonToPaths(geom.coordinates)); + } + } else { + if (idx === 0) { + clipper.addSubjectPaths(polygonToPaths(geom.coordinates)); + } else { + clipper.addClipPaths(polygonToPaths(geom.coordinates)); + } + } }); - if (geoms.length < 2) { - throw new Error("Must have at least 2 geometries"); - } + const tree = new PolyTreeD(); + clipper.execute(ClipType.Union, FillRule.NonZero, tree); - const unioned = polyclip.union(geoms[0], ...geoms.slice(1)); - if (unioned.length === 0) return null; - if (unioned.length === 1) return polygon(unioned[0], options.properties); - else return multiPolygon(unioned, options.properties); + // Return the result as Polygon, MultiPolygon, or null as appropriate + const geom = polyTreeToGeoJSON(tree); + if (geom === null) return null; + return feature(geom, options.properties); } export { union }; diff --git a/packages/turf-union/package.json b/packages/turf-union/package.json index ca470742f2..5dec1e6311 100644 --- a/packages/turf-union/package.json +++ b/packages/turf-union/package.json @@ -63,9 +63,10 @@ }, "dependencies": { "@turf/helpers": "workspace:*", + "@turf/internal": "workspace:*", "@turf/meta": "workspace:*", "@types/geojson": "^7946.0.10", - "polyclip-ts": "^0.16.8", + "clipper2-ts": "^2.0.1", "tslib": "^2.8.1" } } diff --git a/packages/turf-union/test/in/union5.geojson b/packages/turf-union/test/in/union5.geojson new file mode 100644 index 0000000000..0fa4d55ae0 --- /dev/null +++ b/packages/turf-union/test/in/union5.geojson @@ -0,0 +1,91 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + [-79.885712, 32.88766], + [-80.097885, 32.927437], + [-80.153503, 32.82825], + [-80.003128, 32.694288], + [-79.893951, 32.75552], + [-79.885712, 32.88766] + ], + [ + [-80.033715, 32.875508], + [-79.941087, 32.866098], + [-79.916897, 32.783297], + [-80.01425, 32.754522], + [-80.079736, 32.836853], + [-80.033715, 32.875508] + ] + ], + [ + [ + [-80.046825, 32.846002], + [-80.012242, 32.803534], + [-79.965252, 32.807258], + [-79.964808, 32.835201], + [-80.009581, 32.857916], + [-80.046825, 32.846002] + ], + [ + [-80.002268, 32.845442], + [-79.999388, 32.836876], + [-79.984315, 32.8352], + [-79.997836, 32.829426], + [-79.995398, 32.815456], + [-80.004708, 32.82626], + [-80.017562, 32.820299], + [-80.011136, 32.831103], + [-80.020224, 32.838552], + [-80.00914, 32.837435], + [-80.002268, 32.845442] + ] + ], + [ + [ + [-79.936652, 32.964886], + [-80.041397, 32.98246], + [-80.079302, 32.946468], + [-79.963587, 32.919675], + [-79.936652, 32.964886] + ] + ] + ], + "type": "MultiPolygon" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [-79.921417, 32.953944], + [-79.994467, 32.83401], + [-79.973602, 32.760717], + [-79.930344, 32.764759], + [-79.937897, 32.741082], + [-79.805374, 32.723176], + [-79.817734, 32.923402], + [-79.921417, 32.953944] + ], + [ + [-79.902742, 32.913654], + [-79.841373, 32.895333], + [-79.837838, 32.793218], + [-79.884445, 32.75204], + [-79.946398, 32.814046], + [-79.902742, 32.913654] + ] + ], + "type": "Polygon" + } + } + ] +} diff --git a/packages/turf-union/test/out/not-overlapping.geojson b/packages/turf-union/test/out/not-overlapping.geojson index d38e089ee1..e27e248439 100644 --- a/packages/turf-union/test/out/not-overlapping.geojson +++ b/packages/turf-union/test/out/not-overlapping.geojson @@ -6,23 +6,23 @@ "coordinates": [ [ [ - [-80.15350341796875, 32.82825010814964], - [-80.00312805175781, 32.69428812316933], - [-79.89395141601562, 32.75551989829049], - [-79.88571166992188, 32.887659962078956], - [-80.09788513183594, 32.927436533285565], - [-80.15350341796875, 32.82825010814964] + [-79.89395142000001, 32.7555199], + [-79.88571167, 32.88765996], + [-80.09788513000001, 32.92743653], + [-80.15350342, 32.82825011], + [-80.00312805, 32.69428812], + [-79.89395142000001, 32.7555199] ] ], [ [ - [-79.88433837890625, 32.687931474529464], - [-79.79232788085938, 32.679840539897484], - [-79.63233947753906, 32.804590457442565], - [-79.64881896972656, 32.915908931564864], - [-79.78958129882812, 32.913603231028915], - [-79.85618591308594, 32.85997876713845], - [-79.88433837890625, 32.687931474529464] + [-79.63233948, 32.80459046], + [-79.64881897000001, 32.91590893], + [-79.7895813, 32.91360323], + [-79.85618591000001, 32.85997877], + [-79.88433838, 32.68793147], + [-79.79232788, 32.67984054], + [-79.63233948, 32.80459046] ] ] ] diff --git a/packages/turf-union/test/out/union1.geojson b/packages/turf-union/test/out/union1.geojson index 11a16df8e0..950688740e 100644 --- a/packages/turf-union/test/out/union1.geojson +++ b/packages/turf-union/test/out/union1.geojson @@ -5,15 +5,15 @@ "type": "Polygon", "coordinates": [ [ - [-80.15350341796875, 32.82825010814964], - [-80.00312805175781, 32.69428812316933], - [-79.92322780260464, 32.73910022106017], - [-79.80537414550781, 32.7231762754146], - [-79.81773376464844, 32.923402043498875], - [-79.92141723632812, 32.953944317478246], - [-79.94623496447946, 32.89900638172028], - [-80.09788513183594, 32.927436533285565], - [-80.15350341796875, 32.82825010814964] + [-79.9232278, 32.73910022], + [-79.80537415, 32.723176280000004], + [-79.81773376, 32.92340204], + [-79.92141724, 32.95394432], + [-79.94623496, 32.89900637], + [-80.09788513000001, 32.92743653], + [-80.15350342, 32.82825011], + [-80.00312805, 32.69428812], + [-79.9232278, 32.73910022] ] ] } diff --git a/packages/turf-union/test/out/union2.geojson b/packages/turf-union/test/out/union2.geojson index f064ff9c8a..1f4f75dd45 100644 --- a/packages/turf-union/test/out/union2.geojson +++ b/packages/turf-union/test/out/union2.geojson @@ -5,21 +5,21 @@ "type": "Polygon", "coordinates": [ [ - [-80.14389038085938, 32.8149783969858], - [-80.07453918457031, 32.85536439443039], - [-80.00867471875296, 32.84645494258788], - [-79.99171138057724, 32.77876713098755], - [-80.00175476074217, 32.732418508353746], - [-79.9376375650137, 32.741047214297545], - [-79.80537414550781, 32.7231762754146], - [-79.81773376464844, 32.923402043498875], - [-79.91098503795921, 32.950871281288116], - [-79.95025634765625, 32.97007559940924], - [-79.95741485597672, 32.93704020740794], - [-80.03128051757812, 32.936657533381286], - [-80.02726389659406, 32.92063024667495], - [-80.10543823242188, 32.94760622243483], - [-80.14389038085938, 32.8149783969858] + [-79.81773376, 32.92340204], + [-79.91098505000001, 32.95087128], + [-79.95025635, 32.9700756], + [-79.95741485, 32.9370402], + [-80.03128052, 32.93665753], + [-80.02726390000001, 32.92063024], + [-80.10543823, 32.94760622], + [-80.14389038, 32.8149784], + [-80.07453918, 32.85536439], + [-80.00867472, 32.84645494], + [-79.99171138, 32.77876712], + [-80.00175476, 32.73241851], + [-79.93763757, 32.74104721], + [-79.80537415, 32.723176280000004], + [-79.81773376, 32.92340204] ] ] } diff --git a/packages/turf-union/test/out/union3.geojson b/packages/turf-union/test/out/union3.geojson index 583bb0aea4..35bb726a1c 100644 --- a/packages/turf-union/test/out/union3.geojson +++ b/packages/turf-union/test/out/union3.geojson @@ -5,21 +5,21 @@ "type": "Polygon", "coordinates": [ [ - [-80.15350341796875, 32.82825010814964], - [-80.00312805175781, 32.69428812316933], - [-79.92322780260464, 32.73910022106017], - [-79.87698786324371, 32.73285245328464], - [-79.88433837890625, 32.687931474529464], - [-79.79232788085938, 32.679840539897484], - [-79.63233947753906, 32.804590457442565], - [-79.64881896972656, 32.915908931564864], - [-79.78958129882812, 32.913603231028915], - [-79.81582464318822, 32.89247428541929], - [-79.81773376464844, 32.923402043498875], - [-79.92141723632812, 32.953944317478246], - [-79.94623496447946, 32.89900638172028], - [-80.09788513183594, 32.927436533285565], - [-80.15350341796875, 32.82825010814964] + [-79.63233948, 32.80459046], + [-79.64881897000001, 32.91590893], + [-79.7895813, 32.91360323], + [-79.81582464, 32.89247428], + [-79.81773376, 32.92340204], + [-79.92141724, 32.95394432], + [-79.94623496, 32.89900637], + [-80.09788513000001, 32.92743653], + [-80.15350342, 32.82825011], + [-80.00312805, 32.69428812], + [-79.9232278, 32.73910022], + [-79.87698786, 32.73285245], + [-79.88433838, 32.68793147], + [-79.79232788, 32.67984054], + [-79.63233948, 32.80459046] ] ] } diff --git a/packages/turf-union/test/out/union4.geojson b/packages/turf-union/test/out/union4.geojson index 80b68d7a55..cc4fbe58f8 100644 --- a/packages/turf-union/test/out/union4.geojson +++ b/packages/turf-union/test/out/union4.geojson @@ -5,27 +5,27 @@ "type": "Polygon", "coordinates": [ [ - [-75.732, 45.337], - [-75.728, 45.331], - [-75.719, 45.328], - [-75.71, 45.331], - [-75.70745454545455, 45.33481818181818], + [-75.71000000000001, 45.331], + [-75.70745455000001, 45.33481818], [-75.702, 45.333], [-75.693, 45.336], - [-75.689, 45.342], - [-75.693, 45.349], - [-75.69445161290322, 45.34932258064516], - [-75.692, 45.353], + [-75.68900000000001, 45.342], + [-75.693, 45.349000000000004], + [-75.69445161, 45.34932258], + [-75.69200000000001, 45.353], [-75.696, 45.36], [-75.705, 45.362], [-75.714, 45.36], [-75.717, 45.353], [-75.714, 45.347], [-75.71244, 45.34648], - [-75.71342253521127, 45.344760563380284], - [-75.719, 45.346], - [-75.728, 45.344], - [-75.732, 45.337] + [-75.71342253, 45.34476056], + [-75.71900000000001, 45.346000000000004], + [-75.72800000000001, 45.344], + [-75.732, 45.337], + [-75.72800000000001, 45.331], + [-75.71900000000001, 45.328], + [-75.71000000000001, 45.331] ] ] } diff --git a/packages/turf-union/test/out/union5.geojson b/packages/turf-union/test/out/union5.geojson new file mode 100644 index 0000000000..71c63fe283 --- /dev/null +++ b/packages/turf-union/test/out/union5.geojson @@ -0,0 +1,75 @@ +{ + "type": "Feature", + "properties": {}, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + [ + [-79.936652, 32.964886], + [-80.041397, 32.98246], + [-80.079302, 32.946468], + [-79.963587, 32.919675], + [-79.936652, 32.964886] + ] + ], + [ + [ + [-79.92322798000001, 32.73909997], + [-79.805374, 32.723176], + [-79.817734, 32.923402], + [-79.921417, 32.953944], + [-79.95399275, 32.90046089], + [-80.097885, 32.927437], + [-80.153503, 32.828250000000004], + [-80.003128, 32.694288], + [-79.92322798000001, 32.73909997] + ], + [ + [-79.89359686, 32.76119969], + [-79.885712, 32.887660000000004], + [-79.91197654, 32.89258392], + [-79.902742, 32.913654], + [-79.841373, 32.895333], + [-79.837838, 32.793218], + [-79.884445, 32.75204], + [-79.89359686, 32.76119969] + ], + [ + [-80.079736, 32.836853], + [-80.033715, 32.875508], + [-79.97295104, 32.86933504], + [-79.98691138, 32.84641486], + [-80.009581, 32.857916], + [-80.046825, 32.846002], + [-80.012242, 32.803534], + [-79.9863747, 32.805584], + [-79.9751301, 32.76608481], + [-80.01425, 32.754522], + [-80.079736, 32.836853] + ], + [ + [-80.00470800000001, 32.82626], + [-80.017562, 32.820299], + [-80.01113600000001, 32.831103], + [-80.020224, 32.838552], + [-80.00914, 32.837435], + [-80.002268, 32.845442], + [-79.999388, 32.836876000000004], + [-79.99314422, 32.83618174], + [-79.994467, 32.83401], + [-79.99366865, 32.83120562], + [-79.997836, 32.829426], + [-79.99539800000001, 32.815456], + [-80.00470800000001, 32.82626] + ], + [ + [-79.946398, 32.814046], + [-79.93408666, 32.84213624], + [-79.91740183, 32.78502503], + [-79.946398, 32.814046] + ] + ] + ] + } +} diff --git a/packages/turf/package.json b/packages/turf/package.json index 891c4d060f..ff38321967 100644 --- a/packages/turf/package.json +++ b/packages/turf/package.json @@ -80,6 +80,7 @@ "@rollup/plugin-commonjs": "^28.0.3", "@rollup/plugin-node-resolve": "^16.0.1", "@rollup/plugin-terser": "^0.4.4", + "@turf/internal": "workspace:*", "@types/tape": "^5.8.1", "camelcase": "^8.0.0", "documentation": "^14.0.3", diff --git a/patches/clipper2-ts.patch b/patches/clipper2-ts.patch new file mode 100644 index 0000000000..320c8d0d94 --- /dev/null +++ b/patches/clipper2-ts.patch @@ -0,0 +1,90 @@ +diff --git a/dist/Core.js b/dist/Core.js +index f54c7a922c38d7eab2c6a6e1c8277c12f843b111..9eedff6ff2f016c5b5f7a34da132e45437167c20 100644 +--- a/dist/Core.js ++++ b/dist/Core.js +@@ -6,6 +6,9 @@ + * Purpose : Core structures and functions for the Clipper Library * + * License : https://www.boost.org/LICENSE_1_0.txt * + *******************************************************************************/ ++ ++import JSBI from "jsbi"; ++ + // Note: all clipping operations except for Difference are commutative. + export var ClipType; + (function (ClipType) { +@@ -39,11 +42,11 @@ export var PointInPolygonResult; + })(PointInPolygonResult || (PointInPolygonResult = {})); + export var InternalClipper; + (function (InternalClipper) { +- InternalClipper.MaxInt64 = 9223372036854775807n; +- InternalClipper.MaxCoord = Number(InternalClipper.MaxInt64 / 4n); ++ InternalClipper.MaxInt64 = JSBI.BigInt("9223372036854775807"); ++ InternalClipper.MaxCoord = JSBI.toNumber(JSBI.divide(InternalClipper.MaxInt64, JSBI.BigInt(4))); + InternalClipper.max_coord = InternalClipper.MaxCoord; + InternalClipper.min_coord = -InternalClipper.MaxCoord; +- InternalClipper.Invalid64 = Number(InternalClipper.MaxInt64); ++ InternalClipper.Invalid64 = JSBI.toNumber(InternalClipper.MaxInt64); + InternalClipper.floatingPointTolerance = 1E-12; + InternalClipper.defaultMinimumEdgeLength = 0.1; + function crossProduct(pt1, pt2, pt3) { +@@ -77,15 +80,15 @@ export var InternalClipper; + } + if (signAB === 0) + return 0; // both 0 because signs equal +- const bigA = BigInt(a); +- const bigB = BigInt(b); +- const bigC = BigInt(c); +- const bigD = BigInt(d); +- const prod1 = bigA * bigB; +- const prod2 = bigC * bigD; +- if (prod1 === prod2) ++ const bigA = JSBI.BigInt(a); ++ const bigB = JSBI.BigInt(b); ++ const bigC = JSBI.BigInt(c); ++ const bigD = JSBI.BigInt(d); ++ const prod1 = JSBI.multiply(bigA, bigB); ++ const prod2 = JSBI.multiply(bigC, bigD); ++ if (JSBI.equal(prod1, prod2)) + return 0; +- return (prod1 > prod2) ? 1 : -1; ++ return (JSBI.greaterThen(prod1, prod2)) ? 1 : -1; + } + InternalClipper.crossProductSign = crossProductSign; + function checkPrecision(precision) { +@@ -104,13 +107,13 @@ export var InternalClipper; + InternalClipper.triSign = triSign; + function multiplyUInt64(a, b) { + // Fix: a and b might be larger than 2^32, so don't use >>> 0 +- const aBig = BigInt(a); +- const bBig = BigInt(b); +- const res = aBig * bBig; ++ const aBig = JSBI.BigInt(a); ++ const bBig = JSBI.BigInt(b); ++ const res = JSBI.multiply(aBig, bBig); + return { +- lo64: Number(res & 0xffffffffffffffffn), +- hi64: Number(res >> 64n) +- }; ++ lo64: JSBI.toNumber(JSBI.bitwiseAnd(res, JSBI.BigInt("0xffffffffffffffffn"))), ++ hi64: JSBI.toNumber(JSBI.signedRightShift(res, JSBI.BigInt(64))), ++ } + } + InternalClipper.multiplyUInt64 = multiplyUInt64; + // returns true if (and only if) a * b == c * d +@@ -133,11 +136,11 @@ export var InternalClipper; + return false; + if (signAb === 0) + return true; +- const bigA = BigInt(absA); +- const bigB = BigInt(absB); +- const bigC = BigInt(absC); +- const bigD = BigInt(absD); +- return (bigA * bigB) === (bigC * bigD); ++ const bigA = JSBI.BigInt(absA); ++ const bigB = JSBI.BigInt(absB); ++ const bigC = JSBI.BigInt(absC); ++ const bigD = JSBI.BigInt(absD); ++ return JSBI.equal(JSBI.multiply(bigA, bigB), JSBI.multiply(bigC, bigD)); + } + InternalClipper.productsAreEqual = productsAreEqual; + function isCollinear(pt1, sharedPt, pt2) { \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08b02ad069..245d4643fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +patchedDependencies: + clipper2-ts: + hash: 997913062feeb1de5fd5261beeb64bd3c36ed793014e98af5d790ee1eed2e846 + path: patches/clipper2-ts.patch + importers: .: @@ -108,6 +113,40 @@ importers: specifier: ^0.3.0 version: 0.3.0 + packages/internal: + dependencies: + '@types/geojson': + specifier: ^7946.0.10 + version: 7946.0.14 + clipper2-ts: + specifier: ^2.0.1 + version: 2.0.1(patch_hash=997913062feeb1de5fd5261beeb64bd3c36ed793014e98af5d790ee1eed2e846) + jsbi: + specifier: ^4.3.2 + version: 4.3.2 + tslib: + specifier: ^2.8.1 + version: 2.8.1 + devDependencies: + '@babel/core': + specifier: ^7.26.10 + version: 7.26.10 + '@babel/types': + specifier: ^7.26.10 + version: 7.27.0 + '@types/babel__core': + specifier: ^7.20.5 + version: 7.20.5 + '@types/tape': + specifier: ^5.8.1 + version: 5.8.1 + tape: + specifier: ^5.9.0 + version: 5.9.0 + tsup: + specifier: ^8.4.0 + version: 8.4.0(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1) + packages/turf: dependencies: '@turf/along': @@ -464,7 +503,7 @@ importers: version: 7.26.9(@babel/core@7.26.10) '@rollup/plugin-babel': specifier: ^6.0.4 - version: 6.0.4(@babel/core@7.26.10)(rollup@4.40.1) + version: 6.0.4(@babel/core@7.26.10)(@types/babel__core@7.20.5)(rollup@4.40.1) '@rollup/plugin-commonjs': specifier: ^28.0.3 version: 28.0.3(rollup@4.40.1) @@ -474,6 +513,9 @@ importers: '@rollup/plugin-terser': specifier: ^0.4.4 version: 0.4.4(rollup@4.40.1) + '@turf/internal': + specifier: workspace:* + version: link:../internal '@types/tape': specifier: ^5.8.1 version: 5.8.1 @@ -2493,15 +2535,18 @@ importers: '@turf/helpers': specifier: workspace:* version: link:../turf-helpers + '@turf/internal': + specifier: workspace:* + version: link:../internal '@turf/meta': specifier: workspace:* version: link:../turf-meta '@types/geojson': specifier: ^7946.0.10 version: 7946.0.14 - polyclip-ts: - specifier: ^0.16.8 - version: 0.16.8 + clipper2-ts: + specifier: ^2.0.1 + version: 2.0.1(patch_hash=997913062feeb1de5fd5261beeb64bd3c36ed793014e98af5d790ee1eed2e846) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -3261,15 +3306,18 @@ importers: '@turf/helpers': specifier: workspace:* version: link:../turf-helpers + '@turf/internal': + specifier: workspace:* + version: link:../internal '@turf/meta': specifier: workspace:* version: link:../turf-meta '@types/geojson': specifier: ^7946.0.10 version: 7946.0.14 - polyclip-ts: - specifier: ^0.16.8 - version: 0.16.8 + clipper2-ts: + specifier: ^2.0.1 + version: 2.0.1(patch_hash=997913062feeb1de5fd5261beeb64bd3c36ed793014e98af5d790ee1eed2e846) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -6150,15 +6198,18 @@ importers: '@turf/helpers': specifier: workspace:* version: link:../turf-helpers + '@turf/internal': + specifier: workspace:* + version: link:../internal '@turf/meta': specifier: workspace:* version: link:../turf-meta '@types/geojson': specifier: ^7946.0.10 version: 7946.0.14 - polyclip-ts: - specifier: ^0.16.8 - version: 0.16.8 + clipper2-ts: + specifier: ^2.0.1 + version: 2.0.1(patch_hash=997913062feeb1de5fd5261beeb64bd3c36ed793014e98af5d790ee1eed2e846) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -6404,10 +6455,18 @@ packages: resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.25.9': resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.25.9': resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} engines: {node: '>=6.9.0'} @@ -6819,6 +6878,10 @@ packages: resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@colors/colors@1.6.0': resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} @@ -7763,6 +7826,18 @@ packages: '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/benchmark@2.1.5': resolution: {integrity: sha512-cKio2eFB3v7qmKcvIHLUMw/dIx/8bhWPuzpzRT4unCPRTD8VdA9Zb0afxpcxOqR4PixRS7yT42FqGS8BYL8g1w==} @@ -8302,6 +8377,10 @@ packages: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} + clipper2-ts@2.0.1: + resolution: {integrity: sha512-raIgNMpYN/PFYk/T9iRzaG99rf5nlXBWL1FyAdR3wjEYSzJy+pPfolLH5bCdRqCFQqn/eYUsF1jb3cQEMxmWGw==} + engines: {node: '>=14.0.0'} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -9718,6 +9797,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsbi@4.3.2: + resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==} + jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -11882,7 +11964,7 @@ snapshots: '@babel/parser': 7.26.2 '@babel/template': 7.27.0 '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 + '@babel/types': 7.27.0 convert-source-map: 2.0.0 debug: 4.4.0 gensync: 1.0.0-beta.2 @@ -11914,7 +11996,7 @@ snapshots: '@babel/generator@7.26.2': dependencies: '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 + '@babel/types': 7.27.0 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.0.2 @@ -11980,7 +12062,7 @@ snapshots: '@babel/helper-module-imports@7.25.9': dependencies: '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 + '@babel/types': 7.27.0 transitivePeerDependencies: - supports-color @@ -12035,8 +12117,12 @@ snapshots: '@babel/helper-string-parser@7.25.9': {} + '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-validator-identifier@7.25.9': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.25.9': {} '@babel/helper-wrap-function@7.25.9': @@ -12054,7 +12140,7 @@ snapshots: '@babel/parser@7.26.2': dependencies: - '@babel/types': 7.26.0 + '@babel/types': 7.27.0 '@babel/parser@7.27.0': dependencies: @@ -12532,7 +12618,7 @@ snapshots: '@babel/generator': 7.26.2 '@babel/parser': 7.26.2 '@babel/template': 7.27.0 - '@babel/types': 7.26.0 + '@babel/types': 7.27.0 debug: 4.4.0 globals: 11.12.0 transitivePeerDependencies: @@ -12560,6 +12646,11 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@colors/colors@1.6.0': {} '@dabh/diagnostics@2.0.3': @@ -13378,12 +13469,13 @@ snapshots: write-file-atomic: 5.0.1 write-yaml-file: 4.2.0 - '@rollup/plugin-babel@6.0.4(@babel/core@7.26.10)(rollup@4.40.1)': + '@rollup/plugin-babel@6.0.4(@babel/core@7.26.10)(@types/babel__core@7.20.5)(rollup@4.40.1)': dependencies: '@babel/core': 7.26.10 '@babel/helper-module-imports': 7.25.9 '@rollup/pluginutils': 5.1.3(rollup@4.40.1) optionalDependencies: + '@types/babel__core': 7.20.5 rollup: 4.40.1 transitivePeerDependencies: - supports-color @@ -13555,6 +13647,27 @@ snapshots: dependencies: tslib: 2.8.1 + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.27.0 + '@babel/types': 7.27.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.27.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.27.0 + '@babel/types': 7.27.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + '@types/benchmark@2.1.5': {} '@types/concaveman@1.1.6': {} @@ -14159,6 +14272,8 @@ snapshots: cli-width@4.1.0: {} + clipper2-ts@2.0.1(patch_hash=997913062feeb1de5fd5261beeb64bd3c36ed793014e98af5d790ee1eed2e846): {} + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -15753,6 +15868,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsbi@4.3.2: {} + jsesc@3.0.2: {} jsesc@3.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dee51e928d..5eed33654d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,4 @@ packages: - - "packages/*" + - packages/* +patchedDependencies: + clipper2-ts: patches/clipper2-ts.patch