An open API service indexing awesome lists of open source software.

https://github.com/radevgit/nfp

No Fit Polygon
https://github.com/radevgit/nfp

collision collision-detection nfp no-fit-polygon

Last synced: 6 months ago
JSON representation

No Fit Polygon

Awesome Lists containing this project

README

          

# NFP - No Fit Polygon

[![Crates.io](https://img.shields.io/crates/v/nfp.svg?color=blue)](https://crates.io/crates/nfp)
[![Documentation](https://docs.rs/nfp/badge.svg)](https://docs.rs/nfp)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

A Rust library for computing the No Fit Polygon (Minkowski sum) of two convex polygons for nesting and packing optimization.

## What is NFP?

The No Fit Polygon defines the forbidden region where one polygon cannot be placed relative to another without collision. When polygon B's origin is **outside** the NFP, the polygons do **not** overlap. When it's **inside**, they **do** collide.

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
nfp = "0.3"
```

## Quick Start

```rust
use nfp::prelude::*;

// Two convex polygons at origin (CCW orientation)
let square_a = vec![
point(0.0, 0.0),
point(10.0, 0.0),
point(10.0, 10.0),
point(0.0, 10.0),
];

let square_b = vec![
point(0.0, 0.0),
point(5.0, 0.0),
point(5.0, 5.0),
point(0.0, 5.0),
];

// Compute NFP
match NFPConvex::nfp(&square_a, &square_b) {
Ok(nfp) => {
println!("NFP has {} vertices", nfp.len());
// Now use NFP for collision detection:
// point inside NFP → collision, point outside → no collision
}
Err(e) => eprintln!("Error: {}", e),
}
```

## Collision Detection

Once you have the NFP, detect collisions by testing if B's origin is inside or outside:

```rust
use nfp::prelude::*;

fn point_in_polygon(pt: Point, polygon: &[Point]) -> bool {
let mut inside = false;
let mut p1 = polygon[polygon.len() - 1];
for p2 in polygon {
if ((p2.y > pt.y) != (p1.y > pt.y))
&& (pt.x < (p1.x - p2.x) * (pt.y - p2.y) / (p1.y - p2.y) + p2.x)
{
inside = !inside;
}
p1 = *p2;
}
inside
}

// Compute NFP first
let square_a = vec![point(0.0, 0.0), point(10.0, 0.0), point(10.0, 10.0), point(0.0, 10.0)];
let square_b = vec![point(0.0, 0.0), point(5.0, 0.0), point(5.0, 5.0), point(0.0, 5.0)];
let nfp = NFPConvex::nfp(&square_a, &square_b).unwrap();

// Check if placing B at (15.0, 15.0) causes collision
let test_position = point(15.0, 15.0);
if point_in_polygon(test_position, &nfp) {
println!("Collision detected!");
} else {
println!("Safe placement");
}
```

## Requirements

- Both input polygons **must be convex**
- Both polygons must have **at least 3 vertices**
- Polygons should be in **counter-clockwise (CCW) orientation**
- Polygons must be **closed** (last point connects to first conceptually)

## API Reference

`NFPConvex::nfp(poly_a, poly_b) -> Result, NfpError>`

Computes the No Fit Polygon for two convex polygons using Minkowski sum.

Arguments:
- `poly_a` - First convex polygon as slice of points
- `poly_b` - Second convex polygon as slice of points

Returns:
- `Ok(Vec)` - NFP as counter-clockwise convex polygon
- `Err(NfpError)` - If input validation fails

Time Complexity: O(n·m log(n·m)) where n = |A| vertices, m = |B| vertices

`NfpError`

Error enumeration for NFP operations.

Variants:
- `EmptyPolygon` - One or both input polygons are empty
- `InsufficientVertices` - One or both polygons have fewer than 3 vertices

**Example:**
```rust
use nfp::prelude::*;

match NFPConvex::nfp(&a, &b) {
Ok(nfp) => { /* use nfp */ }
Err(NfpError::EmptyPolygon) => eprintln!("Empty polygon provided"),
Err(NfpError::InsufficientVertices) => eprintln!("Polygon needs ≥3 vertices"),
}
```

`Point`

2D coordinate point from the `togo` geometry library.

Fields:
- `x: f64` - X coordinate
- `y: f64` - Y coordinate

`point(x, y) -> Point`

Helper function to create a new Point.

```rust
use nfp::prelude::*;

let p = point(1.5, 2.5);
assert_eq!(p.x, 1.5);
assert_eq!(p.y, 2.5);
```

## Algorithm

The implementation uses the **Minkowski Sum via Vertex Combinations**:

1. Validate inputs (non-empty, convex, ≥3 vertices)
2. Ensure counter-clockwise orientation
3. Negate polygon B (reflection through origin)
4. Generate all vertex sum combinations: {a + b | a ∈ A, b ∈ -B}
5. Compute convex hull of sum points using Graham scan
6. Return convex hull boundary as NFP

## Limitations

- Current version supports **Convex polygons only**

## References

- Minkowski sum: https://en.wikipedia.org/wiki/Minkowski_addition
- No-Fit Polygon: https://en.wikipedia.org/wiki/No-fit_polygon
- Graham scan: https://en.wikipedia.org/wiki/Graham_scan

## Related Projects

NFP is part of the [Nest2D](https://nest2d.com) collection of nesting and packing tools.