polygon2 0.3.0

polygon 2d functions
Documentation
use core::ops::{Add, Div, Mul, Sub};

use num_traits::{Bounded, Float};
use vec2;

use super::{point_to_line_intersection, Intersection};

#[inline]
pub fn closest_edge<T>(points: &[[T; 2]], p: &[T; 2]) -> Intersection<T>
where
    T: Clone + Float + Bounded + PartialOrd,
    for<'a, 'b> &'a T: Div<&'b T, Output = T>
        + Sub<&'b T, Output = T>
        + Add<&'b T, Output = T>
        + Mul<&'b T, Output = T>,
{
    let n = points.len();
    let n_minus_1 = n - 1;
    let px = p[0].clone();
    let py = p[1].clone();

    let mut intersection = Intersection::new();

    let mut i = 0;
    while i < n {
        let p1 = &points[i];
        let p2 = if i == n_minus_1 {
            &points[0]
        } else {
            &points[i + 1]
        };

        point_to_line_intersection(&mut intersection, p, p1, p2, i);

        i += 1;
    }

    if &intersection.distance != &T::zero() {
        intersection.normal[0] = &(&px - &intersection.point[0]) / &intersection.distance;
        intersection.normal[1] = &(&py - &intersection.point[1]) / &intersection.distance;
    } else {
        intersection.normal[0] = T::zero();
        intersection.normal[1] = T::one();
    }

    intersection
}

#[test]
fn test_closest_edge() {
    let points = [[0.5, -0.5], [0.5, 0.5], [-0.5, 0.5], [-0.5, -0.5]];

    let intersection = closest_edge(&points, &[1.0, 0.0]);
    assert_eq!(
        intersection,
        Intersection::from((0, 0.5, [0.5, 0.0], [1.0, 0.0]))
    );

    let intersection = closest_edge(&points, &[0.0, 1.0]);
    assert_eq!(
        intersection,
        Intersection::from((1, 0.5, [0.0, 0.5], [0.0, 1.0]))
    );

    let intersection = closest_edge(&points, &[-1.0, 0.0]);
    assert_eq!(
        intersection,
        Intersection::from((2, 0.5, [-0.5, 0.0], [-1.0, 0.0]))
    );

    let intersection = closest_edge(&points, &[0.0, -1.0]);
    assert_eq!(
        intersection,
        Intersection::from((3, 0.5, [0.0, -0.5], [0.0, -1.0]))
    );
}

#[inline]
pub fn closest_edge_offset_angle<T>(
    points: &[[T; 2]],
    offset: &[T; 2],
    angle: T,
    p: &[T; 2],
) -> Intersection<T>
where
    T: Clone + Float + Bounded + PartialOrd,
    for<'a, 'b> &'a T: Div<&'b T, Output = T>
        + Sub<&'b T, Output = T>
        + Add<&'b T, Output = T>
        + Mul<&'b T, Output = T>,
{
    let n = points.len();
    let n_minus_1 = n - 1;
    let px = p[0];
    let py = p[1];

    let mut b1 = [T::zero(); 2];
    let mut b2 = [T::zero(); 2];

    let mut tmp1 = [T::zero(); 2];
    let mut tmp2 = [T::zero(); 2];

    let mut intersection = Intersection::new();

    let mut i = 0;
    while i < n {
        let p1 = &points[i];
        let p2 = if i == n_minus_1 {
            &points[0]
        } else {
            &points[i + 1]
        };

        tmp1[0] = p1[0];
        tmp1[1] = p1[1];
        vec2::transform_angle(&mut tmp2, &tmp1, &angle);
        vec2::add(&mut b1, offset, &tmp2);

        tmp1[0] = p2[0];
        tmp1[1] = p2[1];
        vec2::transform_angle(&mut tmp2, &tmp1, &angle);
        vec2::add(&mut b2, offset, &tmp2);

        point_to_line_intersection(&mut intersection, p, &b1, &b2, i);

        i += 1;
    }

    if intersection.distance != T::zero() {
        intersection.normal[0] = (px - intersection.point[0]) / intersection.distance;
        intersection.normal[1] = (py - intersection.point[1]) / intersection.distance;
    } else {
        intersection.normal[0] = T::zero();
        intersection.normal[1] = T::one();
    }

    intersection
}

#[test]
fn test_closest_edge_offset_angle() {
    let points = [[0.5, -0.5], [0.5, 0.5], [-0.5, 0.5], [-0.5, -0.5]];

    let intersection = closest_edge_offset_angle(&points, &[0.5, 0.5], 0.0, &[1.5, 0.5]);
    assert_eq!(
        intersection,
        Intersection::from((0, 0.5, [1.0, 0.5], [1.0, 0.0]))
    );

    let intersection = closest_edge_offset_angle(&points, &[0.5, 0.5], 0.0, &[0.5, 1.5]);
    assert_eq!(
        intersection,
        Intersection::from((1, 0.5, [0.5, 1.0], [0.0, 1.0]))
    );

    let intersection = closest_edge_offset_angle(&points, &[0.5, 0.5], 0.0, &[-0.5, 0.5]);
    assert_eq!(
        intersection,
        Intersection::from((2, 0.5, [0.0, 0.5], [-1.0, 0.0]))
    );

    let intersection = closest_edge_offset_angle(&points, &[0.5, 0.5], 0.0, &[0.5, -0.5]);
    assert_eq!(
        intersection,
        Intersection::from((3, 0.5, [0.5, 0.0], [0.0, -1.0]))
    );
}