polyops 0.1.0

Fast Martinez-Rueda polygon clipping: Boolean operations (intersection, union, difference, xor) on polygons and multipolygons over GeoJSON-shaped coordinates. Pure-Rust port of martinez-polygon-clipping.
# PolyOps

Fast polygon Boolean operations in Rust, with first-class Node.js bindings.

PolyOps is a faithful port of [`martinez-polygon-clipping`](https://github.com/w8r/martinez)
(Alex Milevski's JavaScript implementation of the Martinez-Rueda-Feito algorithm)
into idiomatic Rust, with a [`napi-rs`](https://napi.rs) wrapper so the same
engine can be consumed from Node.js without giving up native performance.

> **Status:** published. `polyops` 0.0.4 is on
> [crates.io]https://crates.io/crates/polyops and
> [npm]https://www.npmjs.com/package/polyops (prebuilt binaries for macOS,
> Linux gnu/musl, and Windows), with full behavioral parity against
> `martinez-polygon-clipping@0.8.1` over the upstream fixture corpus. The API
> is still `0.0.x` and may change before `0.1`.

## Operations

```
intersection(subject, clipping)
union       (subject, clipping)
difference  (subject, clipping)
xor         (subject, clipping)
```

All four operate on GeoJSON-shaped `Polygon` or `MultiPolygon` coordinate
arrays, matching the upstream JS API.

## Packages

| Registry   | Name              | Source                  |
|------------|-------------------|-------------------------|
| crates.io  | `polyops`         | `crates/polyops`        |
| npm        | `polyops`         | `crates/polyops-napi`   |

## Performance

`polyops` (Rust, single-thread) runs the upstream `union` benchmarks
**~1.8×–2.9× faster** than `martinez-polygon-clipping@0.8.1`. The Node binding
routes coordinates through typed-array buffers **by default** (only flat data
crosses the N-API boundary), so it's **faster than martinez at every size** —
~1.9× on a small clip-path intersection, ~2–2.6× on large unions — with the
same drop-in, GeoJSON-shaped API:

```js
const polyops = require('polyops'); // drop-in martinez-compatible API, fast by default
polyops.union(subjectCoords, clippingCoords);
```

For pipelines that keep geometry in buffer form, `pack`/`unpack` and the raw
`*Flat` ops are also exported (skip repacking across calls). Full numbers +
methodology in [`BENCHMARKS.md`](BENCHMARKS.md).

## Comparison & when to use

PolyOps is a drop-in, faster replacement for `martinez-polygon-clipping` —
same GeoJSON-shaped API, same results (verified to parity), Rust under the hood:

| | **PolyOps** | martinez-polygon-clipping |
|---|---|---|
| Engine | Rust (native + crates.io) | pure JavaScript |
| Speed (union benchmarks) | **1.8–2.9× (Rust), 1.9–2.6× (Node)** | 1× (baseline) |
| API | drop-in (identical shape) ||
| Output parity | matches `0.8.1` exactly ||
| Modules | ESM + CommonJS | CommonJS |
| Prebuilt platforms | macOS, Linux gnu+musl, Windows | n/a |

**Use PolyOps when** you want `martinez-polygon-clipping` behavior but faster
(Node *or* Rust), with prebuilt native binaries and a maintained codebase, on
substantive polygon workloads (clip paths, GIS, vector geometry).

**Other polygon-Boolean libraries** (different algorithms / trade-offs):
`martinez-polygon-clipping` (the pure-JS reference PolyOps ports),
`polygon-clipping` and `polybooljs` (other pure-JS libraries), and
`clipper2` / `i_overlay` (fast native/Rust, but *not* Martinez-compatible).

## Layout

```
PolyOps/
├── crates/
│   ├── polyops/          pure-Rust crate (algorithm, types, tests)
│   └── polyops-napi/     napi-rs binding, published to npm
├── parity/               Node harness: runs martinez-polygon-clipping@0.8.1
│                         against all upstream fixtures, emits goldens
└── .github/workflows/    CI: cargo test + parity tests
```

## Development

```bash
cargo test          # runs unit + parity tests
cargo bench         # runs benchmarks
cargo clippy        # lints
cargo fmt --check
```

To regenerate the parity goldens against the latest upstream:

```bash
cd parity
npm install
npm run generate
```

## License

MIT. See [`LICENSE`](LICENSE). Credit to Alexander Milevski for the JS
reference implementation and to Martinez/Rueda/Feito for the algorithm.