Skip to content

Commit 4c35e28

Browse files
committed
Preliminary implementation
1 parent 076073c commit 4c35e28

18 files changed

Lines changed: 627 additions & 1323 deletions

docs/NFP_CONVEX.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# NFP for Convex Polygons
2+
3+
## The core concept for convex polygons:
4+
5+
The No-Fit Polygon for two convex polygons can be computed using the **Minkowski Sum** approach. Specifically:
6+
7+
$$\text{NFP}(A, B) = A \oplus (-B)$$
8+
9+
where $\oplus$ is Minkowski sum and $-B$ means B reflected around the origin.
10+
11+
## The algorithm steps:
12+
13+
1. **Reflect B around origin**: Negate all coordinates of B's vertices, then reverse order (to maintain CCW)
14+
15+
2. **Compute convex hull of Minkowski sum**:
16+
- For each vertex of A and each vertex of reflected B, compute their Pairwise sum (vector addition)
17+
- This gives a point cloud of all possible positions
18+
- Compute convex hull of this point cloud
19+
- The convex hull IS the NFP
20+
21+
3. **Alternatively, simpler edge-merging approach**:
22+
- Sort all edges from A and B by angle
23+
- Merge them into one edge sequence (traversing both polygons' boundaries)
24+
- Traverse this merged sequence while accumulating position to trace the NFP boundary
25+
- This avoids computing convex hull explicitly
26+
27+
## Recommended: Edge Merging Approach
28+
29+
```
30+
1. Get all edges from A (as vectors)
31+
2. Get all edges from reflected B (as vectors)
32+
3. Combine into one list, sort by angle (atan2)
33+
4. Start at a reference point
34+
5. Traverse: follow each edge in sequence, tracking current position
35+
6. Each position becomes an NFP vertex
36+
```
37+

docs/PointNFP.md

Lines changed: 0 additions & 147 deletions
This file was deleted.

examples/nfp_20.rs

Lines changed: 0 additions & 153 deletions
This file was deleted.
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
use nfp::prelude::*;
2-
use std::time::Instant;
32

43
/// Number of iterations to run the NFP calculation
54
const ITERATIONS: usize = 1000;
65

76
fn main() {
87

98
// Generate two different 100-edge polygons with fixed seeds
10-
let poly_a = generate_100_edge_polygon(42);
11-
let poly_b = generate_100_edge_polygon(43);
9+
let poly_a = generate_convex_100_edge_polygon(42);
10+
let poly_b = generate_convex_100_edge_polygon(43);
1211

1312
for _ in 0..ITERATIONS {
14-
let _ = NFP::nfp(&poly_a, &poly_b);
13+
let _ = NFPConvex::nfp(&poly_a, &poly_b);
1514
}
1615
}
1716

1817
/// Generate a 100-edge polygon using a fixed seed via bit manipulation
19-
fn generate_100_edge_polygon(seed: u64) -> Vec<Point> {
18+
fn generate_convex_100_edge_polygon(seed: u64) -> Vec<Point> {
2019
use std::f64::consts::PI;
20+
use togo::algo::pointline_convex_hull;
2121

2222
let mut points = Vec::new();
2323
let mut rng_state = seed;
@@ -35,15 +35,16 @@ fn generate_100_edge_polygon(seed: u64) -> Vec<Point> {
3535
points.push(point(radius * angle.cos(), radius * angle.sin()));
3636
}
3737

38-
// Sort by angle from centroid to ensure CCW ordering
38+
// Sort by angle from centroid to ensure CCW ordering (required by convex_hull)
3939
let centroid = compute_centroid(&points);
4040
points.sort_by(|a, b| {
4141
let angle_a = (a.y - centroid.y).atan2(a.x - centroid.x);
4242
let angle_b = (b.y - centroid.y).atan2(b.x - centroid.x);
4343
angle_a.partial_cmp(&angle_b).unwrap_or(std::cmp::Ordering::Equal)
4444
});
4545

46-
points
46+
// Apply convex hull to ensure convex polygon (expects CCW input)
47+
pointline_convex_hull(&points)
4748
}
4849

4950
fn compute_centroid(points: &[Point]) -> Point {

0 commit comments

Comments
 (0)