Skip to content

Latest commit

 

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

iShapeKit

Swift Package that bridges the iShape Rust geometry toolkit (via the bundled i_shape_ffi crate) into native Swift APIs. It ships prebuilt static libraries plus thin Swift wrappers so you can run high-performance polygon Boolean operations on Apple platforms without touching Rust directly.

Current package version: 0.2.6

Installation

dependencies: [
    .package(url: "https://github.com/iShape-Rust/iShape-swift.git", from: "0.2.6")
],
targets: [
    .target(
        name: "YourTarget",
        dependencies: [
            .product(name: "iShapeKit", package: "iShape-swift")
        ]
    )
]

Rebuild the FFI artifacts whenever you change the Rust sources:

cd iShape-swift
./build_ffi.sh

Then build or test with SwiftPM (the script emits static libs for macOS, iOS device, and iOS simulator):

CLANG_MODULE_CACHE_PATH=$(pwd)/.cache/clang swift build --disable-sandbox
CLANG_MODULE_CACHE_PATH=$(pwd)/.cache/clang swift test --disable-sandbox

Quick Start

import iShapeKit

let overlay = IntOverlay()

// Add one subject shape (outer contour plus a hole).
overlay.addSubject([[
    [IntPoint(0, 0), IntPoint(0, 10), IntPoint(10, 10), IntPoint(10, 0)],
    [IntPoint(4, 4), IntPoint(4, 6), IntPoint(6, 6), IntPoint(6, 4)],
]])

overlay.addClip([[
    [IntPoint(5, 0), IntPoint(5, 10), IntPoint(12, 10), IntPoint(12, 0)],
]])

let buffer = FlatShapesBuffer()
overlay.overlay(overlayRule: .union, fillRule: .evenOdd, output: buffer)

let shapes: IntShapes = buffer.toIntShapes()
print(shapes.count)      // -> 1
print(shapes[0].count)   // -> outer contour + one hole

FlatShapesBuffer can be reused across calls and passed over the FFI boundary, while the high-level helpers return Swift-native [[[IntPoint]]] structures for convenience.

Float / CGPoint API

FloatOverlay mirrors the integer API, but takes and returns CGPoint:

import CoreGraphics
import iShapeKit

let overlay = FloatOverlay()
overlay.addSubject([[
    [CGPoint(x: 0, y: 0), CGPoint(x: 0, y: 4), CGPoint(x: 4, y: 4), CGPoint(x: 4, y: 0)],
]])
overlay.addClip([[
    [CGPoint(x: 2, y: 0), CGPoint(x: 2, y: 4), CGPoint(x: 6, y: 4), CGPoint(x: 6, y: 0)],
]])

let result: CGPointShapes? = overlay.overlay(overlayRule: .union, fillRule: .evenOdd)

Stroke Offsets

Use CGPointStrokeOffset for a constant-width path stroke:

let stroked = CGPointStrokeOffset.offsetContours(
    points: [
        CGPoint(x: 0, y: 0),
        CGPoint(x: 10, y: 0),
        CGPoint(x: 10, y: 10),
    ],
    distance: 1,
    isClosedPath: false,
    style: StrokeOffsetStyle(lineJoin: .round(0.2), lineCap: .round(0.2))
)

Use CGPointVariableStrokeOffset when every vertex has its own full stroke width:

let variable = CGPointVariableStrokeOffset.offsetContours(
    vertices: [
        CGPointVariableStrokeVertex(x: 0, y: 0, width: 2),
        CGPointVariableStrokeVertex(x: 10, y: 0, width: 8),
        CGPointVariableStrokeVertex(x: 20, y: 10, width: 4),
    ],
    isClosedPath: false
)

Use overlayHierarchy when the caller also needs immediate nesting links from a floating-point Boolean operation:

let hierarchy = overlay.overlayHierarchy(
    overlayRule: .union,
    fillRule: .nonZero
)

let childIndices = Set(hierarchy?.links.map(\.childShapeIndex) ?? [])
let rootShapes = hierarchy?.shapes.enumerated().compactMap { index, shape in
    childIndices.contains(index) ? nil : shape
}

parentContourIndex is a global index across the flattened contour order of shapes, while the parent and child shape indices address shapes directly.

Convex Decomposition

CGPointConvexDecomposition triangulates shapes, applies Delaunay refinement, and groups the triangles into non-overlapping counter-clockwise convex polygons:

let polygons = CGPointConvexDecomposition.toConvexPolygons(
    shape: [[
        CGPoint(x: 0, y: 0),
        CGPoint(x: 6, y: 0),
        CGPoint(x: 6, y: 2),
        CGPoint(x: 2, y: 2),
        CGPoint(x: 2, y: 6),
        CGPoint(x: 0, y: 6),
    ]]
)

Use the input:output: overload with FlatF64ShapesBuffer to reuse allocated FFI buffers across calls.

About

Bridge exposing Rust iShape polygon tooling to Swift.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages