Skip to content
iShape-RustPublic

About

A fast 2D geometry library in WebAssembly for JavaScript and TypeScript. Supports polygon boolean operations, buffering, and triangulation.

Topics

Resources

Stars

50 stars

Watchers

4 watching

Forks

Repository files navigation

iShape-js

A fast 2D geometry library in WebAssembly for JavaScript and TypeScript. Supports Boolean operations on polygons and Bézier curves, buffering, and triangulation.

Try out iShape with an interactive demo.

Features

  • Boolean Operations: union, intersection, difference, and exclusion.
  • Curves: Boolean operations on lines, quadratic and cubic Bézier curves, and elliptic arcs.
  • Polygons: with holes, self-intersections, and multiple paths.
  • Simplification: removes degenerate vertices and merges collinear edges.
  • Fill Rules: even-odd, non-zero, positive and negative.

Getting Started

Direct include

Download Library Files:

  • ishape_wasm.js
  • ishape_bg_wasm.wasm

You can find it at: pkg

Place Files:

Place these files in a directory that your HTML file can access; in this example, the directory is named ./ishape

NPM

Installation

You can install the iShape library from NPM:

npm install ishape_wasm

The NPM package is available here

Import and Usage

After installing the NPM package, you can import it in your JavaScript or TypeScript file as follows:

import init, { Overlay, OverlayRule, FillRule } from './ishape/ishape_wasm.js';

// Your code here

Example

Here is a simple HTML example that demonstrates how to use the iShape library for union operation. Full example is available here

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>iShape</title>
    <style>
        #result {
            background-color: #f5f5f5;
            border: 1px solid #ccc;
            padding: 10px;
            white-space: pre-wrap;
            font-family: monospace;
        }
        textarea {
            width: 100%;
            height: 150px;
            padding: 10px;
            font-family: monospace;
            margin-bottom: 10px;
        }
    </style>
    <script type="module">
        import init, { Overlay, OverlayRule, FillRule} from './ishape/ishape_wasm.js';

        init();

        document.getElementById('union').addEventListener('click', () => {
            const subjInput = document.getElementById('subjInput').value;
            const clipInput = document.getElementById('clipInput').value;

            const subj = JSON.parse(subjInput);
            const clip = JSON.parse(clipInput);

            const overlay = Overlay.new_with_subj_and_clip(subj, clip);

            // apply union operation
            const union = overlay.overlay(OverlayRule.Union, FillRule.EvenOdd);

            // add more operations if required
            // ...

            const resultText = JSON.stringify(union, null, 2);
            document.getElementById('result').innerText = `Result:\n${resultText}`;
        });
    </script>
</head>
<body>
    <textarea id="subjInput" placeholder='Enter "subj" polygon here...'>[[[200, 300], [200, 100], [400, 100], [400, 300]]]</textarea>
    <textarea id="clipInput" placeholder='Enter "clip" polygon here...'>[[[300, 400], [300, 200], [500, 200], [500, 400]]]</textarea>
    <button id="union">Union</button>
    <pre id="result"></pre>
</body>
</html>

Explanation:

Import classes and initialize the WebAssembly module using init(). Use the imported classes to perform geometric operations.

Uniform Triangulation and Mesh Relaxation

Build a Delaunay mesh with a target edge length, then relax its interior vertices while keeping outer and hole boundaries fixed:

import init, { Triangulator } from 'ishape_wasm';

await init();
const triangulator = new Triangulator();
const delaunay = triangulator.uniform_triangulate(shape, 40);
triangulator.free();

const relaxation = delaunay.relax_mut({ maxIterations: 24, tolerance: 0 });
const mesh = delaunay.to_triangulation();
delaunay.free();

uniform_triangulate(path, edgeLength) accepts a contour, shape, or multiple shapes and returns Delaunay directly. It splits boundary edges and adds an interior lattice. The target edge length must be finite, positive, and above the integer engine's coordinate precision. For the previous refinement method, use triangulate(path).into_delaunay() and refine_with_circumcenters(maxArea).

relax_mut() modifies the mesh in place and returns { iterations, converged }. Both options are optional: maxIterations defaults to 8, and tolerance to 0. Invalid options throw before modifying the mesh. The Tessellation demo defaults to Uniform with relaxation enabled. Both subdivision methods can be compared using the same triangle, centroid-net, and convex-polygon views.

Curve Boolean Operations

CurveBuilder uses the familiar Canvas-style path methods. Every contour must be closed before calling build(). The returned CurveGeometry is reusable: it can be passed directly into another Boolean operation without converting it to JavaScript data first.

import init, {
    CurveBuilder,
    CurveOverlay,
    OverlayRule,
    FillRule,
} from 'ishape_wasm';

await init();

const subjectBuilder = new CurveBuilder();
subjectBuilder.moveTo(0, 0);
subjectBuilder.bezierCurveTo(25, -30, 75, -30, 100, 0);
subjectBuilder.lineTo(100, 80);
subjectBuilder.lineTo(0, 80);
subjectBuilder.closeContour();
const subject = subjectBuilder.build();

const clipBuilder = new CurveBuilder();
clipBuilder.moveTo(40, -10);
clipBuilder.lineTo(120, -10);
clipBuilder.lineTo(120, 50);
clipBuilder.lineTo(40, 50);
clipBuilder.closeContour();
const clip = clipBuilder.build();

const operation = new CurveOverlay(subject, clip);
const result = operation.overlay(OverlayRule.Intersect, FillRule.NonZero);

// Ordinary typed JavaScript data for rendering or serialization.
console.log(result.toData());

Use quadraticCurveTo() for quadratic Bézier segments, ellipticArcTo() for an arc in the active contour, or addEllipse() to append a complete ellipse as a new closed contour. Advanced callers can use CurveOverlay.withScale(), setApproximation(), and conversionReport() to control and inspect the discrete precision model. Approximation settings are optional, so callers only specify what they need:

operation.setApproximation({ minChordLength: 0.001 });

To resolve self-intersections without a clip, use CurveOverlay.fromSubject(geometry).resolveSubject(fillRule).

Overlay Rules

A,B A ∪ B A ∩ B A - B B - A A ⊕ B
AB Union Intersection Difference Inverse Difference Exclusion

About

A fast 2D geometry library in WebAssembly for JavaScript and TypeScript. Supports polygon boolean operations, buffering, and triangulation.

Topics

Resources

Stars

50 stars

Watchers

4 watching

Forks

Releases

Packages

Used by

Contributors

Languages