use togo::prelude::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NfpError {
EmptyPolygon,
InsufficientVertices,
}
impl std::fmt::Display for NfpError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NfpError::EmptyPolygon => write!(f, "Polygons cannot be empty"),
NfpError::InsufficientVertices => write!(f, "Polygons must have at least 3 vertices"),
}
}
}
impl std::error::Error for NfpError {}
pub struct NFPConvex;
impl NFPConvex {
pub fn nfp(poly_a: &[Point], poly_b: &[Point]) -> Result<Vec<Point>, NfpError> {
if poly_a.is_empty() || poly_b.is_empty() {
return Err(NfpError::EmptyPolygon);
}
if poly_a.len() < 3 || poly_b.len() < 3 {
return Err(NfpError::InsufficientVertices);
}
Ok(Self::compute(poly_a, poly_b))
}
fn compute(a: &[Point], b: &[Point]) -> Vec<Point> {
let mut b_negated = b.to_vec();
b_negated.reverse();
for pt in &mut b_negated {
pt.x = -pt.x;
pt.y = -pt.y;
}
let mut sum_points = Vec::with_capacity(a.len() * b_negated.len());
for &a_v in a {
for &b_v in &b_negated {
sum_points.push(point(a_v.x + b_v.x, a_v.y + b_v.y));
}
}
pointline_convex_hull(&sum_points)
}
}
#[allow(dead_code)]
pub fn to_arcline(vertices: &[Point]) -> Vec<togo::prelude::Arc> {
use togo::prelude::*;
let mut arcline: Vec<Arc> = Vec::new();
if vertices.is_empty() {
return arcline;
}
for i in 0..vertices.len() {
let current = vertices[i];
let next = vertices[(i + 1) % vertices.len()];
let p1 = point(current.x, current.y);
let p2 = point(next.x, next.y);
let arc = arcseg(p1, p2);
arcline.push(arc);
}
arcline
}