use kalast::base::object_3d::Object3D;
use kalast::MINIMUM_PRECISION;
use std::path::Path;

#[test]
fn parse_object_file() {
    // test vertices, faces, centers, normals, areas and sphericals: shape,
    // first and last points
    let path = Path::new("tests/rsc/obj/dimorphos.obj");
    let mut obj = Object3D::new(path);
    let number_faces = obj.number_faces();

    // test vertices
    assert_eq!((3, 4902), obj.vertices().shape());

    let first_vertex = obj.vertices().column(0);
    let mut first_it = first_vertex.iter();
    assert_eq!(*first_it.next().unwrap(), 0.);
    assert_eq!(*first_it.next().unwrap(), 0.);
    assert_eq!(*first_it.next().unwrap(), 63.);

    let last_vertex = obj.vertices().column(obj.vertices().ncols() - 1);
    let mut last_it = last_vertex.iter();
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        5.0133295,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -0.24838692,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -62.875687,
        epsilon = MINIMUM_PRECISION,
    ));

    // test faces
    assert_eq!((3, 9800), obj.faces().shape());

    let first_face = obj.faces().column(0);
    let mut first_it = first_face.iter();
    assert_eq!(*first_it.next().unwrap(), 2);
    assert_eq!(*first_it.next().unwrap(), 51);
    assert_eq!(*first_it.next().unwrap(), 0);

    let last_face = obj.faces().column(number_faces - 1);
    let mut last_it = last_face.iter();
    assert_eq!(*last_it.next().unwrap(), 4900);
    assert_eq!(*last_it.next().unwrap(), 50);
    assert_eq!(*last_it.next().unwrap(), 49);

    // test centers
    assert_eq!((3, 9800), obj.centers().shape());

    let first_center = obj.centers().column(0);
    let mut first_it = first_center.iter();
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        3.3455236752827964,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        0.08279563983281453,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        62.91712443033854,
        epsilon = MINIMUM_PRECISION,
    ));

    let last_center = obj.centers().column(number_faces - 1);
    let mut last_it = last_center.iter();
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        8.35225788752237,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -0.16526451706886292,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -62.6273803710937,
        epsilon = MINIMUM_PRECISION,
    ));

    // test normals
    assert_eq!((3, 9800), obj.normals().shape());

    let first_normal = obj.normals().column(0);
    let mut first_it = first_normal.iter();
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        0.024740049494588287,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        0.0009872650203700852,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        0.999693430637005,
        epsilon = MINIMUM_PRECISION,
    ));

    let last_normal = obj.normals().column(number_faces - 1);
    let mut last_it = last_normal.iter();
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        0.07423527350796591,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -0.002962544162202277,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -0.997236354882474,
        epsilon = MINIMUM_PRECISION,
    ));

    // test areas
    assert_eq!((9800, 1), obj.areas().shape());
    assert_eq!(0.6240450566112805, obj.areas()[0]);
    assert_eq!(1.2437683977019571, obj.areas()[number_faces - 1]);

    // test sphericals
    assert_eq!((3, 9800), obj.sphericals().0.shape());

    let first_spherical = obj.sphericals().vector(0);
    let mut first_it = first_spherical.iter();
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        0.024743134624245038,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        1.5176566219709358,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *first_it.next().unwrap(),
        63.00606264767349,
        epsilon = MINIMUM_PRECISION,
    ));

    let last_spherical = obj.sphericals().vector(number_faces - 1);
    let mut last_it = last_spherical.iter();
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -0.01978422557857265,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        -1.438188702497458,
        epsilon = MINIMUM_PRECISION
    ));
    assert!(relative_eq!(
        *last_it.next().unwrap(),
        63.18208841377389,
        epsilon = MINIMUM_PRECISION,
    ));
}
