aboutsummaryrefslogtreecommitdiff
path: root/src/geometry/z_order.rs
blob: 669354768f1ca23854ba0da319eb4cd925b40e6a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use num_traits::float::FloatCore;
use std::cmp::Ordering;

#[allow(dead_code)] // We don't use this currently, but migth in the future.
pub fn z_cmp_ints(lhs: &[usize], rhs: &[usize]) -> Ordering {
    assert_eq!(
        lhs.len(),
        rhs.len(),
        "Cannot compare array with different lengths."
    );

    let mut msd = 0;

    for dim in 1..rhs.len() {
        if less_msb(lhs[msd] ^ rhs[msd], lhs[dim] ^ rhs[dim]) {
            msd = dim;
        }
    }

    lhs[msd].cmp(&rhs[msd])
}

fn less_msb(x: usize, y: usize) -> bool {
    x < y && x < (x ^ y)
}

// Fast construction of k-Nearest Neighbor Graphs for Point Clouds
// Michael Connor, Piyush Kumar
// Algorithm 1
//
// http://compgeom.com/~piyush/papers/tvcg_stann.pdf
pub fn z_cmp_floats(p1: &[f32], p2: &[f32]) -> Option<Ordering> {
    assert_eq!(
        p1.len(),
        p2.len(),
        "Cannot compare array with different lengths."
    );
    let mut x = 0;
    let mut dim = 0;

    for j in 0..p1.len() {
        let y = xor_msb_float(p1[j], p2[j]);
        if x < y {
            x = y;
            dim = j;
        }
    }

    p1[dim].partial_cmp(&p2[dim])
}

fn xor_msb_float(fa: f32, fb: f32) -> i16 {
    let (mantissa1, exponent1, _sign1) = fa.integer_decode();
    let (mantissa2, exponent2, _sign2) = fb.integer_decode();
    let x = exponent1; // To keep the same notation as the paper.
    let y = exponent2; // To keep the same notation as the paper.

    if x == y {
        let z = msdb(mantissa1, mantissa2);
        x - z
    } else if y < x {
        x
    } else {
        y
    }
}

fn msdb(x: u64, y: u64) -> i16 {
    64i16 - (x ^ y).leading_zeros() as i16
}