contourable 0.8.0

A library for differentiable functions
Documentation
use std::marker::PhantomData;

use nalgebra::{ComplexField, Point2};
use num_dual::{DualNum, DualNumFloat};

use crate::{Aabb, Contour};

#[derive(Debug, Clone)]
pub struct Line<D, F>
where
    D: DualNum<F>,
    F: DualNumFloat,
{
    p0: nalgebra::Point2<D>,
    p1: nalgebra::Point2<D>,

    _f: std::marker::PhantomData<F>,
}

impl<D, F> Line<D, F>
where
    D: DualNum<F> + ComplexField<RealField = D>,
    F: DualNumFloat,
{
    pub fn new(p0: nalgebra::Point2<D>, p1: nalgebra::Point2<D>) -> Self {
        Self {
            p0,
            p1,
            _f: std::marker::PhantomData,
        }
    }
    pub fn length(&self) -> D {
        (&self.p1 - &self.p0).norm()
    }
}

impl<L, D, F> Contour<D, F> for Line<L, F>
where
    L: DualNum<F> + PartialOrd + ComplexField<RealField = L>,
    D: DualNum<F> + ComplexField<RealField = D> + From<L>,
    F: DualNumFloat,
{
    fn position(&self, s: &D) -> nalgebra::Point2<D> {
        self.p0.map(D::from) + ((&self.p1 - &self.p0) / self.length()).map(D::from) * s.clone()
    }

    fn s_interval(&self) -> (D, D) {
        (D::zero(), Contour::length(self))
    }

    fn aabb(&self, _n: u32, _f: PhantomData<D>) -> Aabb<D> {
        let (xmin, xmax) = match self.p0.x < self.p1.x {
            true => (self.p0.x.clone(), self.p1.x.clone()),
            false => (self.p1.x.clone(), self.p0.x.clone()),
        };
        let (ymin, ymax) = match self.p0.y.re() < self.p1.y.re() {
            true => (self.p0.y.clone(), self.p1.y.clone()),
            false => (self.p1.y.clone(), self.p0.y.clone()),
        };
        Aabb {
            min: Point2::new(D::from(xmin), D::from(ymin)),
            max: Point2::new(D::from(xmax), D::from(ymax)),
        }
    }
}

#[cfg(test)]
mod tests {

    use approx::assert_relative_eq;
    use num_dual::Dual64;

    use super::*;

    #[test]
    fn test_chain_f64() {
        let p0 = nalgebra::Point2::new(1.0, 2.0);
        let p1 = nalgebra::Point2::new(9.0, 6.0);
        let line = Line::new(p0, p1);

        let points = line.divide(0.0, line.length(), 5);

        assert_relative_eq!(points[0].x, 1.0, epsilon = 1e-12);
        assert_relative_eq!(points[0].y, 2.0, epsilon = 1e-12);

        assert_relative_eq!(points[1].x, 3.0, epsilon = 1e-12);
        assert_relative_eq!(points[1].y, 3.0, epsilon = 1e-12);

        assert_relative_eq!(points[2].x, 5.0, epsilon = 1e-12);
        assert_relative_eq!(points[2].y, 4.0, epsilon = 1e-12);

        assert_relative_eq!(points[3].x, 7.0, epsilon = 1e-12);
        assert_relative_eq!(points[3].y, 5.0, epsilon = 1e-12);

        assert_relative_eq!(points[4].x, 9.0, epsilon = 1e-12);
        assert_relative_eq!(points[4].y, 6.0, epsilon = 1e-12);
    }
    #[test]
    fn test_chain_dual64() {
        let p0 = nalgebra::Point2::new(Dual64::from_re(1.0), Dual64::from_re(2.0));
        let p1 = nalgebra::Point2::new(Dual64::from_re(9.0), Dual64::from_re(6.0));
        let line = Line::new(p0, p1);

        let points = line.divide(Dual64::from_re(0.0), line.length(), 5);

        assert_relative_eq!(points[0].x.re(), 1.0, epsilon = 1e-12);
        assert_relative_eq!(points[0].y.re(), 2.0, epsilon = 1e-12);

        assert_relative_eq!(points[1].x.re(), 3.0, epsilon = 1e-12);
        assert_relative_eq!(points[1].y.re(), 3.0, epsilon = 1e-12);

        assert_relative_eq!(points[2].x.re(), 5.0, epsilon = 1e-12);
        assert_relative_eq!(points[2].y.re(), 4.0, epsilon = 1e-12);

        assert_relative_eq!(points[3].x.re(), 7.0, epsilon = 1e-12);
        assert_relative_eq!(points[3].y.re(), 5.0, epsilon = 1e-12);

        assert_relative_eq!(points[4].x.re(), 9.0, epsilon = 1e-12);
        assert_relative_eq!(points[4].y.re(), 6.0, epsilon = 1e-12);
    }

    #[test]
    fn test_aabb() {
        let p0 = nalgebra::Point2::new(Dual64::from_re(1.0), Dual64::from_re(10.0));
        let p1 = nalgebra::Point2::new(Dual64::from_re(9.0), Dual64::from_re(2.0));
        let line = Line::new(p0, p1);

        let aabb = line.aabb(0, PhantomData::<Dual64>);
        assert_relative_eq!(aabb.min.x.re(), 1.0, epsilon = 1e-12);
        assert_relative_eq!(aabb.min.y.re(), 2.0, epsilon = 1e-12);
        assert_relative_eq!(aabb.max.x.re(), 9.0, epsilon = 1e-12);
        assert_relative_eq!(aabb.max.y.re(), 10.0, epsilon = 1e-12);
    }
}