diff --git a/CHANGELOG.md b/CHANGELOG.md index 92e86d5..1a9c2a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## main (unreleased) -- IN PROGRESS: fix the packaging issues with v0.15.4 +- fix the packaging issues with v0.15.4 ## v0.15.5 (2023-12-16) diff --git a/bench/bench.js b/bench/bench.js index aa9db0c..f82d8cd 100644 --- a/bench/bench.js +++ b/bench/bench.js @@ -4,7 +4,7 @@ import { default as load } from "load-json-file" import { default as Benchmark } from "benchmark" import { default as jstsUnion } from "@turf/union" import { default as w8r } from "martinez-polygon-clipping" -import { default as mfogel } from "../dist/polygon-clipping.esm.js" +import { default as mfogel } from "polygon-clipping" /** * Benchmark results ( c9b02e5 ) @@ -43,7 +43,7 @@ const options = { }, } -const holeHole = load.sync("./bench/fixtures/hole_hole.geojson") +const holeHole = load.sync("./fixtures/hole_hole.geojson") new Benchmark.Suite("Hole_Hole", options) .add("mfogel", () => { mfogel.union( @@ -62,8 +62,8 @@ new Benchmark.Suite("Hole_Hole", options) }) .run() -const asia = load.sync("./bench/fixtures/asia.geojson") -const unionPoly = load.sync("./bench/fixtures/asia_unionPoly.geojson") +const asia = load.sync("./fixtures/asia.geojson") +const unionPoly = load.sync("./fixtures/asia_unionPoly.geojson") new Benchmark.Suite("Asia union", options) .add("mfogel", () => { mfogel.union( @@ -80,7 +80,7 @@ new Benchmark.Suite("Asia union", options) .add("JSTS", () => jstsUnion(asia.features[0], unionPoly)) .run() -const states = load.sync("./bench/fixtures/states_source.geojson") +const states = load.sync("./fixtures/states_source.geojson") new Benchmark.Suite("States clip", options) .add("mfogel", () => { mfogel.union( diff --git a/bench/package-lock.json b/bench/package-lock.json new file mode 100644 index 0000000..42995cf --- /dev/null +++ b/bench/package-lock.json @@ -0,0 +1,53 @@ +{ + "name": "bench", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "polygon-clipping": "file:.." + } + }, + "..": { + "version": "0.15.5", + "license": "MIT", + "dependencies": { + "splaytree": "^3.1.0" + }, + "devDependencies": { + "@babel/cli": "^7.23.4", + "@babel/core": "^7.23.6", + "@babel/preset-env": "^7.23.6", + "@rollup/plugin-babel": "^5.3.1", + "@rollup/plugin-commonjs": "^21.1.0", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.3.0", + "@turf/difference": "^5.1.5", + "@turf/intersect": "^5.1.6", + "@turf/meta": "^6.5.0", + "@turf/union": "^5.1.5", + "@vitejs/plugin-vue": "^3.2.0", + "babel-jest": "^27.5.1", + "benchmark": "^2.1.4", + "eslint": "^8.56.0", + "eslint-config-prettier": "^8.10.0", + "eslint-plugin-vue": "^8.7.1", + "jest": "^27.5.1", + "leaflet": "^1.9.4", + "load-json-file": "^6.2.0", + "martinez-polygon-clipping": "^0.7.3", + "npm-run-all": "^4.1.5", + "prettier": "^2.8.8", + "robust-predicates": "^3.0.2", + "rollup": "^2.79.1", + "rollup-plugin-terser": "^7.0.2", + "vite": "^3.2.7", + "vue": "^3.3.12" + } + }, + "node_modules/polygon-clipping": { + "resolved": "..", + "link": true + } + } +} diff --git a/bench/package.json b/bench/package.json new file mode 100644 index 0000000..66182ce --- /dev/null +++ b/bench/package.json @@ -0,0 +1,6 @@ +{ + "type": "module", + "dependencies": { + "polygon-clipping": "file:.." + } +} diff --git a/dist/polygon-clipping.cjs.js b/dist/polygon-clipping.cjs.js index cd842b8..02c2ab1 100644 --- a/dist/polygon-clipping.cjs.js +++ b/dist/polygon-clipping.cjs.js @@ -1,7 +1,6 @@ 'use strict'; var SplayTree = require('splaytree'); -var robustPredicates = require('robust-predicates'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } @@ -52,17 +51,17 @@ const getBboxOverlap = (b1, b2) => { * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON */ -let epsilon = Number.EPSILON; +let epsilon$1 = Number.EPSILON; // IE Polyfill -if (epsilon === undefined) epsilon = Math.pow(2, -52); -const EPSILON_SQ = epsilon * epsilon; +if (epsilon$1 === undefined) epsilon$1 = Math.pow(2, -52); +const EPSILON_SQ = epsilon$1 * epsilon$1; /* FLP comparator */ const cmp = (a, b) => { // check if they're both 0 - if (-epsilon < a && a < epsilon) { - if (-epsilon < b && b < epsilon) { + if (-epsilon$1 < a && a < epsilon$1) { + if (-epsilon$1 < b && b < epsilon$1) { return 0; } } @@ -138,6 +137,272 @@ class CoordRounder { // singleton available by import const rounder = new PtRounder(); +const epsilon = 1.1102230246251565e-16; +const splitter = 134217729; +const resulterrbound = (3 + 8 * epsilon) * epsilon; + +// fast_expansion_sum_zeroelim routine from oritinal code +function sum(elen, e, flen, f, h) { + let Q, Qnew, hh, bvirt; + let enow = e[0]; + let fnow = f[0]; + let eindex = 0; + let findex = 0; + if ((fnow > enow) === (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + let hindex = 0; + if (eindex < elen && findex < flen) { + if ((fnow > enow) === (fnow > -enow)) { + Qnew = enow + Q; + hh = Q - (Qnew - enow); + enow = e[++eindex]; + } else { + Qnew = fnow + Q; + hh = Q - (Qnew - fnow); + fnow = f[++findex]; + } + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + while (eindex < elen && findex < flen) { + if ((fnow > enow) === (fnow > -enow)) { + Qnew = Q + enow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (enow - bvirt); + enow = e[++eindex]; + } else { + Qnew = Q + fnow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (fnow - bvirt); + fnow = f[++findex]; + } + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Qnew = Q + enow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (enow - bvirt); + enow = e[++eindex]; + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Qnew = Q + fnow; + bvirt = Qnew - Q; + hh = Q - (Qnew - bvirt) + (fnow - bvirt); + fnow = f[++findex]; + Q = Qnew; + if (hh !== 0) { + h[hindex++] = hh; + } + } + if (Q !== 0 || hindex === 0) { + h[hindex++] = Q; + } + return hindex; +} + +function estimate(elen, e) { + let Q = e[0]; + for (let i = 1; i < elen; i++) Q += e[i]; + return Q; +} + +function vec(n) { + return new Float64Array(n); +} + +const ccwerrboundA = (3 + 16 * epsilon) * epsilon; +const ccwerrboundB = (2 + 12 * epsilon) * epsilon; +const ccwerrboundC = (9 + 64 * epsilon) * epsilon * epsilon; + +const B = vec(4); +const C1 = vec(8); +const C2 = vec(12); +const D = vec(16); +const u = vec(4); + +function orient2dadapt(ax, ay, bx, by, cx, cy, detsum) { + let acxtail, acytail, bcxtail, bcytail; + let bvirt, c, ahi, alo, bhi, blo, _i, _j, _0, s1, s0, t1, t0, u3; + + const acx = ax - cx; + const bcx = bx - cx; + const acy = ay - cy; + const bcy = by - cy; + + s1 = acx * bcy; + c = splitter * acx; + ahi = c - (c - acx); + alo = acx - ahi; + c = splitter * bcy; + bhi = c - (c - bcy); + blo = bcy - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acy * bcx; + c = splitter * acy; + ahi = c - (c - acy); + alo = acy - ahi; + c = splitter * bcx; + bhi = c - (c - bcx); + blo = bcx - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + B[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + B[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + B[2] = _j - (u3 - bvirt) + (_i - bvirt); + B[3] = u3; + + let det = estimate(4, B); + let errbound = ccwerrboundB * detsum; + if (det >= errbound || -det >= errbound) { + return det; + } + + bvirt = ax - acx; + acxtail = ax - (acx + bvirt) + (bvirt - cx); + bvirt = bx - bcx; + bcxtail = bx - (bcx + bvirt) + (bvirt - cx); + bvirt = ay - acy; + acytail = ay - (acy + bvirt) + (bvirt - cy); + bvirt = by - bcy; + bcytail = by - (bcy + bvirt) + (bvirt - cy); + + if (acxtail === 0 && acytail === 0 && bcxtail === 0 && bcytail === 0) { + return det; + } + + errbound = ccwerrboundC * detsum + resulterrbound * Math.abs(det); + det += (acx * bcytail + bcy * acxtail) - (acy * bcxtail + bcx * acytail); + if (det >= errbound || -det >= errbound) return det; + + s1 = acxtail * bcy; + c = splitter * acxtail; + ahi = c - (c - acxtail); + alo = acxtail - ahi; + c = splitter * bcy; + bhi = c - (c - bcy); + blo = bcy - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acytail * bcx; + c = splitter * acytail; + ahi = c - (c - acytail); + alo = acytail - ahi; + c = splitter * bcx; + bhi = c - (c - bcx); + blo = bcx - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + u[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + u[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + u[2] = _j - (u3 - bvirt) + (_i - bvirt); + u[3] = u3; + const C1len = sum(4, B, 4, u, C1); + + s1 = acx * bcytail; + c = splitter * acx; + ahi = c - (c - acx); + alo = acx - ahi; + c = splitter * bcytail; + bhi = c - (c - bcytail); + blo = bcytail - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acy * bcxtail; + c = splitter * acy; + ahi = c - (c - acy); + alo = acy - ahi; + c = splitter * bcxtail; + bhi = c - (c - bcxtail); + blo = bcxtail - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + u[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + u[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + u[2] = _j - (u3 - bvirt) + (_i - bvirt); + u[3] = u3; + const C2len = sum(C1len, C1, 4, u, C2); + + s1 = acxtail * bcytail; + c = splitter * acxtail; + ahi = c - (c - acxtail); + alo = acxtail - ahi; + c = splitter * bcytail; + bhi = c - (c - bcytail); + blo = bcytail - bhi; + s0 = alo * blo - (s1 - ahi * bhi - alo * bhi - ahi * blo); + t1 = acytail * bcxtail; + c = splitter * acytail; + ahi = c - (c - acytail); + alo = acytail - ahi; + c = splitter * bcxtail; + bhi = c - (c - bcxtail); + blo = bcxtail - bhi; + t0 = alo * blo - (t1 - ahi * bhi - alo * bhi - ahi * blo); + _i = s0 - t0; + bvirt = s0 - _i; + u[0] = s0 - (_i + bvirt) + (bvirt - t0); + _j = s1 + _i; + bvirt = _j - s1; + _0 = s1 - (_j - bvirt) + (_i - bvirt); + _i = _0 - t1; + bvirt = _0 - _i; + u[1] = _0 - (_i + bvirt) + (bvirt - t1); + u3 = _j + _i; + bvirt = u3 - _j; + u[2] = _j - (u3 - bvirt) + (_i - bvirt); + u[3] = u3; + const Dlen = sum(C2len, C2, 4, u, D); + + return D[Dlen - 1]; +} + +function orient2d(ax, ay, bx, by, cx, cy) { + const detleft = (ay - cy) * (bx - cx); + const detright = (ax - cx) * (by - cy); + const det = detleft - detright; + + const detsum = Math.abs(detleft + detright); + if (Math.abs(det) >= ccwerrboundA * detsum) return det; + + return -orient2dadapt(ax, ay, bx, by, cx, cy, detsum); +} + /* Cross Product of two vectors with first point at origin */ const crossProduct = (a, b) => a.x * b.y - a.y * b.x; @@ -146,7 +411,7 @@ const dotProduct = (a, b) => a.x * b.x + a.y * b.y; /* Comparator for two vectors with same starting point */ const compareVectorAngles = (basePt, endPt1, endPt2) => { - const res = robustPredicates.orient2d(basePt.x, basePt.y, endPt1.x, endPt1.y, endPt2.x, endPt2.y); + const res = orient2d(basePt.x, basePt.y, endPt1.x, endPt1.y, endPt2.x, endPt2.y); if (res > 0) return -1; if (res < 0) return 1; return 0; diff --git a/package.json b/package.json index 2d37c7b..e07fb49 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "polygon-clipping", "version": "0.15.5", "description": "Apply boolean Polygon clipping operations (intersection, union, difference, xor) to your Polygons & MultiPolygons.", - "type": "module", "main": "dist/polygon-clipping.cjs.js", "module": "dist/polygon-clipping.esm.js", "browser": "dist/polygon-clipping.umd.js", @@ -17,7 +16,7 @@ "lint:prettier": "prettier --check ./* ./.eslintrc.cjs ./.github", "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", "test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand", - "bench": "node bench/bench.js", + "bench": "cd bench && npm install && node bench.js", "prepublishOnly": "npm-run-all --serial lint test build docs:build bench" }, "files": [ diff --git a/rollup.config.js b/rollup.config.js index 82460a1..f2f5b29 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,4 +1,4 @@ -import resolve from "@rollup/plugin-node-resolve" +import { nodeResolve } from "@rollup/plugin-node-resolve" import { babel } from "@rollup/plugin-babel" import { terser } from "rollup-plugin-terser" import pkg from "./package.json" @@ -11,7 +11,7 @@ export default [ file: pkg.browser, format: "umd", }, - plugins: [resolve(), babel({ babelHelpers: "bundled" })], + plugins: [nodeResolve(), babel({ babelHelpers: "bundled" })], }, { input: "src/index.js", @@ -21,26 +21,35 @@ export default [ format: "umd", sourcemap: true, }, - plugins: [resolve(), babel({ babelHelpers: "bundled" }), terser()], + plugins: [nodeResolve(), babel({ babelHelpers: "bundled" }), terser()], }, { input: "src/index.js", - output: [ - { - file: pkg.main, - format: "cjs", - }, - { - file: pkg.module, - format: "es", - }, + output: { + file: pkg.main, + format: "cjs", + exports: "default", + }, + plugins: [ + nodeResolve({ resolveOnly: ["robust-predicates"] }), + babel({ + babelHelpers: "bundled", + exclude: ["node_modules/**"], + }), ], + }, + { + input: "src/index.js", + output: { + file: pkg.module, + format: "es", + }, plugins: [ babel({ babelHelpers: "bundled", exclude: ["node_modules/**"], }), ], - external: ["splaytree"], + external: ["robust-predicates", "splaytree"], }, ] diff --git a/src/package.json b/src/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/src/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/test/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +}