{"_id":"@duranta-public/react-native-polygon-clipping","_rev":"4-48f4844b98d0b95d69b6cbc7803b63af","name":"@duranta-public/react-native-polygon-clipping","dist-tags":{"latest":"0.4.1"},"versions":{"0.2.0":{"name":"@duranta-public/react-native-polygon-clipping","version":"0.2.0","keywords":["react-native","turbo-module","polygon","clipping","geometry","martinez","boolean-operations","union","intersection","difference"],"author":{"name":"Duranta","email":"alex@getduranta.com"},"license":"BSD-1-Clause","_id":"@duranta-public/react-native-polygon-clipping@0.2.0","maintainers":[{"name":"cyberax","email":"b@alex.net"}],"homepage":"https://github.com/GetDuranta/react-native-polygon-clipping#readme","bugs":{"url":"https://github.com/GetDuranta/react-native-polygon-clipping/issues"},"dist":{"shasum":"54219d33f54eb993c21b7f6b77d378dc0c948602","tarball":"https://registry.npmjs.org/@duranta-public/react-native-polygon-clipping/-/react-native-polygon-clipping-0.2.0.tgz","fileCount":69,"integrity":"sha512-jJWbZDu8tF0XyGsonzso5g6OU1eDkWtBNqkaoChiACAQdSy1h52M3kX1CnYqcOWIqv1pPbiicdfGpci0M0+Jug==","signatures":[{"sig":"MEYCIQCYEzw6zr8bQJUr3i3mdp4uFWksUORnhg29Fbj6TnoitAIhALvUdcPSrzDzivIvsMrx4qu4+ef8O/rAtv3nL0onAMEU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":486297},"main":"lib/commonjs/index.js","types":"lib/typescript/src/index.d.ts","module":"lib/module/index.js","source":"src/index.ts","gitHead":"f0bdde594e7a5fada6392205c695c8862f09509a","scripts":{"test":"test/run-tests.sh","codegen":"react-native codegen","prepare":"bob build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"cyberax","email":"b@alex.net"},"repository":{"url":"git+https://github.com/GetDuranta/react-native-polygon-clipping.git","type":"git"},"_npmVersion":"11.17.0","description":"Fast polygon clipping (union, intersection, difference, xor) for React Native and web: pure C++ Turbo Module with a TypeScript fallback","directories":{},"_nodeVersion":"26.5.0","dependencies":{"splaytree":"^3.1.2","robust-predicates":"^3.0.2"},"react-native":"src/index.ts","codegenConfig":{"name":"PolygonClippingSpec","type":"modules","android":{"javaPackageName":"com.duranta.polygonclipping"},"jsSrcsDir":"src","outputDir":{"ios":"ios/generated","android":"android/generated"},"includesGeneratedCode":true},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","typescript":"^5.9.2","@types/react":"^19.1.0","react-native":"0.86.2","react-native-builder-bob":"^0.40.13","@react-native-community/cli":"^20.0.0"},"peerDependencies":{"react":"*","react-native":">=0.76.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native-polygon-clipping_0.2.0_1787106572193_0.8780056953562441","host":"s3://npm-registry-packages-npm-production"},"react-native-builder-bob":{"output":"lib","source":"src","targets":["commonjs","module",["typescript",{"project":"tsconfig.build.json"}],"codegen"]}},"0.3.0":{"name":"@duranta-public/react-native-polygon-clipping","version":"0.3.0","keywords":["react-native","turbo-module","polygon","clipping","geometry","martinez","boolean-operations","union","intersection","difference"],"author":{"name":"Duranta","email":"alex@getduranta.com"},"license":"BSD-1-Clause","_id":"@duranta-public/react-native-polygon-clipping@0.3.0","maintainers":[{"name":"cyberax","email":"b@alex.net"}],"homepage":"https://github.com/GetDuranta/react-native-polygon-clipping#readme","bugs":{"url":"https://github.com/GetDuranta/react-native-polygon-clipping/issues"},"dist":{"shasum":"26c931ac01376fabb59c40689ff73eabb79b998d","tarball":"https://registry.npmjs.org/@duranta-public/react-native-polygon-clipping/-/react-native-polygon-clipping-0.3.0.tgz","fileCount":76,"integrity":"sha512-3tKxFRRQqNCjc0EL+pFfymHe9aIqdIzNbiesbOxiDpjuv7T5BOgwQkPoQpqFdXBcpW74Nh+cYEafecF3OB82zQ==","signatures":[{"sig":"MEQCIAYiBC3l0H6caCFwvWbp9chYr5oXqVx87+PEySjXAhsOAiBJ1sxZp/1dqaFJn7n62aKcKKwZQ0RJpAZiVIJy4hfjoQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":514239},"main":"lib/commonjs/index.js","types":"lib/typescript/src/index.d.ts","module":"lib/module/index.js","source":"src/index.ts","gitHead":"102982bcae73dd17de13c8389c79acc08fff8276","scripts":{"test":"test/run-tests.sh","codegen":"react-native codegen","prepare":"bob build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"cyberax","email":"b@alex.net"},"repository":{"url":"git+https://github.com/GetDuranta/react-native-polygon-clipping.git","type":"git"},"_npmVersion":"11.17.0","description":"Fast polygon clipping (union, intersection, difference, xor) for React Native and web: pure C++ Turbo Module with a TypeScript fallback","directories":{},"_nodeVersion":"26.5.0","dependencies":{"splaytree":"^3.1.2","robust-predicates":"^3.0.2"},"react-native":"src/index.ts","codegenConfig":{"name":"PolygonClippingSpec","type":"modules","android":{"javaPackageName":"com.duranta.polygonclipping"},"jsSrcsDir":"src","outputDir":{"ios":"ios/generated","android":"android/generated"},"includesGeneratedCode":true},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","typescript":"^5.9.2","@types/react":"^19.1.0","react-native":"0.86.2","react-native-builder-bob":"^0.40.13","@react-native-community/cli":"^20.0.0"},"peerDependencies":{"react":"*","react-native":">=0.76.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native-polygon-clipping_0.3.0_1787112394511_0.6709597643089174","host":"s3://npm-registry-packages-npm-production"},"react-native-builder-bob":{"output":"lib","source":"src","targets":["commonjs","module",["typescript",{"project":"tsconfig.build.json"}],"codegen"]}},"0.4.0":{"name":"@duranta-public/react-native-polygon-clipping","version":"0.4.0","keywords":["react-native","turbo-module","polygon","clipping","geometry","martinez","boolean-operations","union","intersection","difference"],"author":{"name":"Duranta","email":"alex@getduranta.com"},"license":"BSD-1-Clause","_id":"@duranta-public/react-native-polygon-clipping@0.4.0","maintainers":[{"name":"cyberax","email":"b@alex.net"}],"homepage":"https://github.com/GetDuranta/react-native-polygon-clipping#readme","bugs":{"url":"https://github.com/GetDuranta/react-native-polygon-clipping/issues"},"dist":{"shasum":"69ce23ec4a0ccad3f4e9706766b46dcee7920e7e","tarball":"https://registry.npmjs.org/@duranta-public/react-native-polygon-clipping/-/react-native-polygon-clipping-0.4.0.tgz","fileCount":76,"integrity":"sha512-H/IPABzVRbbKlH9l7unmGZzot/15ew3MtSjpALaDG+cwREesNrxnRu3lxmMVFpaYKREb8npQNeNrtXOnAxhpqg==","signatures":[{"sig":"MEYCIQDL0atPRfUxrK6CAjtFS3asxujm9RhSBq3jy4qPkGdxHwIhAP4YP5eDuk1/tj7IUvfh/pfT+Qu3nQ5QpA9k2JQFZe7l","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":528081},"main":"lib/commonjs/index.js","types":"lib/typescript/src/index.d.ts","module":"lib/module/index.js","source":"src/index.ts","gitHead":"8ddf0ff0a61365b2df731d53debe639da9527eb7","scripts":{"test":"test/run-tests.sh","codegen":"react-native codegen","prepare":"bob build","typecheck":"tsc --noEmit"},"_npmUser":{"name":"cyberax","email":"b@alex.net"},"repository":{"url":"git+https://github.com/GetDuranta/react-native-polygon-clipping.git","type":"git"},"_npmVersion":"11.17.0","description":"Fast polygon clipping (union, intersection, difference, xor) for React Native and web: pure C++ Turbo Module with a TypeScript fallback","directories":{},"_nodeVersion":"26.5.0","dependencies":{"splaytree":"^3.1.2","robust-predicates":"^3.0.2"},"react-native":"src/index.ts","codegenConfig":{"name":"PolygonClippingSpec","type":"modules","android":{"javaPackageName":"com.duranta.polygonclipping"},"jsSrcsDir":"src","outputDir":{"ios":"ios/generated","android":"android/generated"},"includesGeneratedCode":true},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"react":"19.2.3","typescript":"^5.9.2","@types/react":"^19.1.0","react-native":"0.86.2","react-native-builder-bob":"^0.40.13","@react-native-community/cli":"^20.0.0"},"peerDependencies":{"react":"*","react-native":">=0.76.0"},"_npmOperationalInternal":{"tmp":"tmp/react-native-polygon-clipping_0.4.0_1787114153624_0.9198252328333327","host":"s3://npm-registry-packages-npm-production"},"react-native-builder-bob":{"output":"lib","source":"src","targets":["commonjs","module",["typescript",{"project":"tsconfig.build.json"}],"codegen"]}},"0.4.1":{"name":"@duranta-public/react-native-polygon-clipping","version":"0.4.1","description":"Fast polygon clipping (union, intersection, difference, xor) for React Native and web: pure C++ Turbo Module with a TypeScript fallback","main":"lib/commonjs/index.js","module":"lib/module/index.js","types":"lib/typescript/src/index.d.ts","react-native":"src/index.ts","source":"src/index.ts","scripts":{"typecheck":"tsc --noEmit","codegen":"react-native codegen","test":"test/run-tests.sh","prepare":"bob build"},"keywords":["react-native","turbo-module","polygon","clipping","geometry","martinez","boolean-operations","union","intersection","difference"],"repository":{"type":"git","url":"git+https://github.com/GetDuranta/react-native-polygon-clipping.git"},"author":{"name":"Duranta","email":"alex@getduranta.com"},"license":"BSD-1-Clause","homepage":"https://github.com/GetDuranta/react-native-polygon-clipping#readme","publishConfig":{"access":"public"},"devDependencies":{"@react-native-community/cli":"^20.0.0","@types/react":"^19.1.0","react":"19.2.3","react-native":"0.86.2","react-native-builder-bob":"^0.40.13","typescript":"^5.9.2"},"peerDependencies":{"react":"*","react-native":">=0.76.0"},"codegenConfig":{"name":"PolygonClippingSpec","type":"modules","jsSrcsDir":"src","outputDir":{"ios":"ios/generated","android":"android/generated"},"android":{"javaPackageName":"com.duranta.polygonclipping"},"includesGeneratedCode":true},"react-native-builder-bob":{"source":"src","output":"lib","targets":["commonjs","module",["typescript",{"project":"tsconfig.build.json"}],"codegen"]},"dependencies":{"robust-predicates":"^3.0.2","splaytree":"^3.1.2"},"gitHead":"c8ef453a4be7af99aeb250416923a1a1d4520b21","_id":"@duranta-public/react-native-polygon-clipping@0.4.1","bugs":{"url":"https://github.com/GetDuranta/react-native-polygon-clipping/issues"},"_nodeVersion":"26.5.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-hsSrHmdlvHqlWKznKcgbcHQd4wHAnrpzVErGpIdjKhU//Hl758yUnpYXyDQl0uDIs1RGDA+id0qDf1sBEib3sw==","shasum":"fd07c881371f045e67641aa98ddf5d3245ef28f4","tarball":"https://registry.npmjs.org/@duranta-public/react-native-polygon-clipping/-/react-native-polygon-clipping-0.4.1.tgz","fileCount":76,"unpackedSize":528453,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHCIr+ybmkS/kknXmTmwi0ifVBbcYVoJWQNb+3AQW134AiBXrZ+42SuupDdTvx8jLATAIQWEyAJpeM/BDHZE7gIVJQ=="}]},"_npmUser":{"name":"cyberax","email":"b@alex.net"},"directories":{},"maintainers":[{"name":"cyberax","email":"b@alex.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/react-native-polygon-clipping_0.4.1_1787123003816_0.02566837031483815"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-19T02:29:32.074Z","modified":"2026-08-19T07:03:24.138Z","0.2.0":"2026-08-19T02:29:32.342Z","0.3.0":"2026-08-19T04:06:34.652Z","0.4.0":"2026-08-19T04:35:53.786Z","0.4.1":"2026-08-19T07:03:23.971Z"},"bugs":{"url":"https://github.com/GetDuranta/react-native-polygon-clipping/issues"},"author":{"name":"Duranta","email":"alex@getduranta.com"},"license":"BSD-1-Clause","homepage":"https://github.com/GetDuranta/react-native-polygon-clipping#readme","keywords":["react-native","turbo-module","polygon","clipping","geometry","martinez","boolean-operations","union","intersection","difference"],"repository":{"type":"git","url":"git+https://github.com/GetDuranta/react-native-polygon-clipping.git"},"description":"Fast polygon clipping (union, intersection, difference, xor) for React Native and web: pure C++ Turbo Module with a TypeScript fallback","maintainers":[{"name":"cyberax","email":"b@alex.net"}],"readme":"# @duranta-public/react-native-polygon-clipping\n\nFast boolean operations on polygons — union, intersection, difference, xor —\nfor React Native, implemented as a **pure C++ Turbo Module** (no Java/Kotlin,\nno Swift/ObjC wrappers around the algorithm, synchronous JSI calls), with a\n**TypeScript fallback** that runs the same algorithm wherever the native\nmodule isn't available: web bundles, Node, Jest, the old architecture. The\npackage can therefore be used as the single polygon-clipping dependency of a\ncodebase that targets both React Native and the web.\n\nThe clipping core is a line-faithful C++ translation of the\n[Martinez-Rueda-Feito](https://doi.org/10.1016/j.advengsoft.2013.04.004)\nsweep-line algorithm from the\n[`polygon-clipping`](https://github.com/mfogel/polygon-clipping) library\n(MIT), with:\n\n- epsilon snapping (1e-12, relative) of near-coincident coordinates, which\n  prevents the sweep-line failures that floating-point noise causes on\n  real-world geographic inputs;\n- the robust [`robust-predicates`](https://github.com/mourner/robust-predicates)\n  `orient2d` for collinearity decisions (exact-precision, ISC);\n- iteration guards against the infinite loops that round-off errors can\n  otherwise cause;\n- iterative (not recursive) state propagation, safe for mobile thread stacks.\n\nThe C++ port is **bit-exact** with its TypeScript reference across a\ndifferential corpus of 265 fixed, random, degenerate, and chained-operation\ncases (see *Testing* below). In a Node/V8 comparison on identical inputs it\nis ~1.7× faster than the JIT-compiled TypeScript; on Hermes, where JS runs\ninterpreted, expect one to two orders of magnitude.\n\n## Requirements\n\n- For the native module: React Native **>= 0.76** with the New Architecture\n  enabled (pure C++ Turbo Module autolinking). Works with Expo SDK 52+\n  (expo-modules-autolinking supports pure C++ dependencies).\n- Everywhere else (web, Node >= 18, Jest) the TypeScript implementation is\n  used automatically; no React Native required in that dependency graph.\n\n## Installation\n\n```sh\nnpm install @duranta-public/react-native-polygon-clipping\ncd ios && pod install\n```\n\nNo other setup: the module autolinks on both platforms (Android via the\n`cxxModule*` autolinking config, iOS via `registerCxxModuleToGlobalModuleMap`).\nCodegen artifacts are shipped in the package (`includesGeneratedCode: true`),\nso no extra codegen step runs in your app.\n\n## Usage\n\nGeoJSON-style nested geometry (drop-in for the `polygon-clipping` package):\n\n```ts\nimport { union, intersection, difference, xor } from \"@duranta-public/react-native-polygon-clipping\";\n\nconst subject = [[[0, 0], [2, 0], [2, 2], [0, 2], [0, 0]]];   // Polygon\nconst clip = [[[1, 1], [3, 1], [3, 3], [1, 3], [1, 1]]];\n\nconst result = intersection(subject, clip);                    // MultiPolygon\n```\n\nPacked flat-coordinate geometry (faster — no per-vertex array allocation):\n\n```ts\nimport {\n  intersectionPacked,\n  differencePacked,\n  unionPacked,\n  xorPacked,\n  type PackedCoords,\n} from \"@duranta-public/react-native-polygon-clipping\";\n\nconst square: PackedCoords = {\n  ringLengths: [5], // coordinate pairs per ring; first ring is the exterior\n  packedCoordinates: [0, 0, 2, 0, 2, 2, 0, 2, 0, 0],\n};\n\nconst result: PackedCoords[] = differencePacked([square], [clip]);\n```\n\nBulk splitting — clips many subject polygons against a set of clip polygons\nin a single native call (one JS↔native crossing instead of two per\nsubject×clip pair):\n\n```ts\nimport { splitEachPacked, differenceEachPacked } from \"@duranta-public/react-native-polygon-clipping\";\n\n// Per subject polygon, iterates the clips in order: intersects the current\n// remainder with the clip and, when non-empty, subtracts the intersection.\nconst results = splitEachPacked(subjects, clips);\n// results[i] = {\n//   outside:  PackedCoords[]  pieces of subjects[i] outside all clips\n//                             (verbatim copy of the input when untouched),\n//   inside:   PackedCoords[]  intersection pieces carved out, in clip order,\n//   touched:  boolean         false = no clip modified this subject,\n//   failures: number          clip steps skipped due to topology errors\n//                             (their intersections remain in `inside`),\n// }\n\n// Same loop without collecting the inside pieces in the result:\nconst diffs = differenceEachPacked(subjects, clips); // { outside, touched, failures }[]\n```\n\nIntersection failures propagate as exceptions; difference failures are\ncounted per subject and that clip step is skipped, so one degenerate\ngeometry doesn't discard the rest of the batch.\n\nWhen per-subject attribution isn't needed, `splitMergedPacked` is much\nfaster: it treats the subjects as one multipolygon and the clips as\nanother, so the sweep-line structures are built once per operation (two\nsweeps total) instead of per subject×clip pair:\n\n```ts\nimport { splitMergedPacked } from \"@duranta-public/react-native-polygon-clipping\";\n\nconst { outside, inside } = splitMergedPacked(subjects, clips);\n// outside = union(subjects) − union(clips)\n// inside  = union(subjects) ∩ union(clips)\n```\n\nTrade-offs vs `splitEachPacked`: results aren't attributed to individual\nsubjects, overlapping/touching subjects merge in the output, coordinates\nare normalized even for subjects no clip touches, and a topology error\nanywhere fails the whole operation (catch it and fall back to\n`splitEachPacked` when robustness matters).\n\nNotes:\n\n- Input rings may be open or closed; output rings are always closed\n  (first point repeated at the end). Exterior rings are counter-clockwise,\n  interior rings clockwise.\n- All functions are synchronous and safe to call from render/gesture code.\n- On invalid input or internal topology failure the functions throw an\n  `Error` with the same messages as `polygon-clipping` (e.g.\n  `\"Unable to complete output ring…\"`), so existing error handling keeps\n  working.\n- `isNativePolygonClippingAvailable()` reports which implementation is in\n  use (false means the TypeScript fallback).\n\n## Architecture\n\n```\nsrc/index.ts                   public API\nsrc/implementation.ts          web/Node entry: TypeScript engine\nsrc/implementation.native.ts   React Native entry: Turbo Module, falling\n                               back to the TypeScript engine when absent\nsrc/polygon-clipping.ts        the TypeScript engine (reference for the C++)\nsrc/NativePolygonClipping.ts   Turbo Module spec (codegen input)\ncpp/PolygonClippingImpl.*      the Turbo Module (decode → clip → encode)\ncpp/core/polyclip.*            the clipping algorithm (RN-independent)\ncpp/core/orient2d.*            robust orientation predicate\nandroid/CMakeLists.txt         builds the C++ into the app (autolinked)\nandroid/generated, ios/generated  shipped codegen artifacts\nios/OnLoad.mm                  registers the module on iOS\n```\n\nPlatform selection uses the standard `.native.ts` convention: Metro (and\njest-expo) resolve `implementation.native.ts`; web bundlers and Node resolve\n`implementation.ts`, whose import graph never touches `react-native`.\nGeometry crosses the JSI boundary as a single flat double array per call.\n\nThe core (`cpp/core`) has no React Native dependencies and builds with any\nC++17 compiler; the algorithm requires **FP contraction disabled**\n(`-ffp-contract=off`, already set in the Android CMake and the podspec) to\nkeep exact IEEE-754 double semantics.\n\n`ClipOptions::robustComparePoint` selects an experimental variant that uses\nexact `orient2d` for point-vs-segment tests (as\n[polyclip-ts](https://github.com/luizbarboza/polyclip-ts) does). It is off\nby default: differential testing showed the exact predicate can conflict\nwith the epsilon-snapped geometry on chained operations and cause\n\"Unable to complete output ring\" failures the default mode doesn't have.\n\n## Testing\n\n`test/run-tests.sh` builds and runs host-side tests: built-in unit tests\nplus a differential harness that replays fixtures generated from the bundled\nTypeScript implementation (`test/gen-fixtures.mjs`, requires `npm install`\nand Node >= 23.6 for TypeScript type stripping) and requires bit-exact\noutput from the C++ port.\n`test/bench.mjs` and `polyclip_test fixtures.txt bench` run the same corpus\nthrough both implementations for timing.\n\n## Regenerating codegen artifacts\n\nAfter changing `src/NativePolygonClipping.ts`:\n\n```sh\nnpx react-native codegen   # or: yarn prepare (react-native-builder-bob)\n```\n\n## License\n\nBSD-1-Clause. Contains code derived from `polygon-clipping` (MIT) and\n`robust-predicates` (ISC) — see [LICENSE](LICENSE) for third-party notices.\n","readmeFilename":"README.md"}