martini 0.2.0

RTIN mesh generation for terrain data based on the Martini algorithm
Documentation
use approx::assert_abs_diff_eq;
use image::load_from_memory;
use martini::{FloatType, Martini};

const IMAGE: &[u8] = include_bytes!("./fuji.png");

fn get_height_from_image(x: usize, y: usize, size: usize, img: &[u8]) -> FloatType {
    let x = x.min(size - 2);
    let y = y.min(size - 2);
    let i = y * (size - 1) + x;

    let k = i * 4;
    let r = img[k] as FloatType;
    let g = img[k + 1] as FloatType;
    let b = img[k + 2] as FloatType;
    (r * 256. * 256. + g * 256. + b) / 10. - 10000.
}

// Same test with https://github.com/mapbox/martini/blob/f0d6dcaeb656b4d256c0da5bfe53de9262c4a8f1/test/test.js
#[test]
fn it_should_generate_mesh() {
    let img = load_from_memory(IMAGE).unwrap();
    let width = img.width();
    let img = img.as_bytes();

    let size = width + 1;
    let mut martini = Martini::new(size);
    let tile = martini.create_terrain(|x, y| get_height_from_image(x, y, size as usize, img));
    let (vertices, indices, _uvs) = tile.construct_mesh(&mut martini, 500., &mut |(u, v)| {
        let size = size as FloatType;
        let h = get_height_from_image(
            (u * size) as usize,
            ((1. - v) * size) as usize,
            size as usize,
            img,
        );
        let size = size - 1.;
        (size * u, size * (1. - v), h)
    });

    assert_float_array(
        &vertices,
        &[
            320.0, 64.0, 1361.4004, 256.0, 128.0, 1949.7002, 320.0, 128.0, 2472.2998, 384.0, 128.0,
            1668.9004, 256.0, 0.0, 1087.0, 288.0, 160.0, 2864.0, 256.0, 192.0, 1825.5996, 288.0,
            192.0, 2765.2998, 320.0, 192.0, 3276.7002, 304.0, 176.0, 3583.7002, 256.0, 256.0,
            1315.5, 288.0, 224.0, 2030.4004, 352.0, 160.0, 2566.2998, 320.0, 160.0, 3337.0, 512.0,
            0.0, 961.0, 384.0, 0.0, 956.0996, 128.0, 128.0, 893.0, 128.0, 0.0, 911.5, 64.0, 64.0,
            1699.7998, 64.0, 0.0, 1083.0, 0.0, 0.0, 497.7998, 32.0, 32.0, 725.5, 192.0, 192.0,
            1058.5996, 384.0, 384.0, 912.2002, 512.0, 256.0, 699.9004, 384.0, 256.0, 1451.9004,
            320.0, 320.0, 1092.4004, 320.0, 256.0, 1650.7998, 512.0, 512.0, 270.4004, 512.0, 128.0,
            1143.2002, 448.0, 192.0, 1099.7998, 384.0, 192.0, 1822.9004, 128.0, 384.0, 174.0,
            256.0, 512.0, 53.09961, 256.0, 384.0, 501.0996, 0.0, 512.0, 389.5996, 128.0, 256.0,
            531.5996, 64.0, 192.0, 681.2998, 0.0, 256.0, 883.5, 64.0, 128.0, 897.7998, 32.0, 96.0,
            1524.5, 0.0, 128.0, 1240.2002, 32.0, 64.0, 1505.5, 16.0, 48.0, 1572.9004, 0.0, 64.0,
            1377.5996, 0.0, 32.0, 1090.7998,
        ],
    );
    assert_unsigned_array(
        &indices,
        &[
            0, 1, 2, 3, 0, 2, 4, 1, 0, 5, 6, 7, 7, 8, 9, 5, 7, 9, 1, 6, 5, 6, 10, 11, 11, 8, 7, 6,
            11, 7, 12, 2, 13, 8, 12, 13, 3, 2, 12, 2, 1, 5, 13, 5, 9, 8, 13, 9, 2, 5, 13, 3, 14,
            15, 15, 4, 0, 3, 15, 0, 16, 4, 17, 18, 17, 19, 19, 20, 21, 18, 19, 21, 16, 17, 18, 1,
            16, 22, 22, 10, 6, 1, 22, 6, 4, 16, 1, 23, 24, 25, 26, 25, 27, 10, 26, 27, 23, 25, 26,
            28, 24, 23, 29, 3, 30, 24, 29, 30, 14, 3, 29, 8, 25, 31, 31, 3, 12, 8, 31, 12, 27, 8,
            11, 10, 27, 11, 25, 8, 27, 25, 24, 30, 30, 3, 31, 25, 30, 31, 32, 33, 34, 10, 32, 34,
            35, 33, 32, 33, 28, 23, 34, 23, 26, 10, 34, 26, 33, 23, 34, 36, 16, 37, 38, 36, 37, 36,
            10, 22, 16, 36, 22, 39, 18, 40, 41, 39, 40, 16, 18, 39, 42, 21, 43, 44, 42, 43, 18, 21,
            42, 21, 20, 45, 45, 44, 43, 21, 45, 43, 44, 41, 40, 40, 18, 42, 44, 40, 42, 41, 38, 37,
            37, 16, 39, 41, 37, 39, 38, 35, 32, 32, 10, 36, 38, 32, 36,
        ],
    );
}

fn assert_float_array(a: &[f32], b: &[f32]) {
    assert_eq!(a.len(), b.len(), "Array lengths differ");
    for (i, v) in a.iter().enumerate() {
        assert_abs_diff_eq!(v, &b[i], epsilon = 0.1);
    }
}

fn assert_unsigned_array(a: &[u32], b: &[u32]) {
    assert_eq!(a.len(), b.len(), "Array lengths differ");
    for (i, v) in a.iter().enumerate() {
        if v != &b[i] {
            panic!("Index {}: {} != {}", i, v, b[i]);
        }
    }
}