How can I interpolate elevation of points in a grid

Hello,
I have the elevation of reference points in a 2D square grid, and I would like to be able to interpolate the elevation of any points in that grid. As far as I understand, the spline crate should be able to help me, but I don't understand how to write a 2D -> 1D interpolation hello word. I didn't know what splines (the mathematical object) was before discovering this crate, so it may be the source of my confusion.

It seems like the spline crate is only for 1d interpolation. You can bilinearly interpolate with something like this:

/// x1, y1, x2, y2 forms a rectangle of coordinates
/// v11 represents the value at x1, y1
/// v12 represents the value at x1, y2
/// v21 represents the value at x2, y1
/// v22 represents the value at x2, y2
struct BilinearData {
    x1: f64,
    y1: f64,
    x2: f64,
    y2: f64,
    v11: f64,
    v12: f64,
    v21: f64,
    v22: f64,
}

// approximates the value of the function f at x,y using bilinear interpolation
fn interpolate(x: f64, y: f64, f: BilinearData) -> f64 {
    let dx1 = x - f.x1;
    let dx2 = f.x2 - x;
    let dy1 = y - f.y1;
    let dy2 = f.y2 - y;
    let scaled = f.v11 * dx2 * dy2
               + f.v21 * dx1 * dy2
               + f.v12 * dx2 * dy1
               + f.v22 * dx1 * dy1;
    scaled / ((f.x2 - f.x1) * (f.y2 - f.y1))
}
2 Likes

The spline crate implements methods for cgmath::Vector2. With a bit more research, this is what I got, but it still doesn't work.

use cgmath::Vector2;

let coordinates: Vec<Vector2<f64>> = vec![
    Vector2::new(0.0, 0.0), Vector2::new(0.0, 0.1), Vector2::new(0.0, 0.2), Vector2::new(0.0, 0.3),
    Vector2::new(1.0, 0.0), Vector2::new(1.0, 0.1), Vector2::new(1.0, 0.2), Vector2::new(1.0, 0.3),
    Vector2::new(2.0, 0.0), Vector2::new(2.0, 0.1), Vector2::new(2.0, 0.2), Vector2::new(2.0, 0.3),
    Vector2::new(3.0, 0.0), Vector2::new(3.0, 0.1), Vector2::new(3.0, 0.2), Vector2::new(3.0, 0.3),
];  
    
let alti_array: Vec<f64> = vec![
    00.0, 01.0, 02.0, 03.0,
    10.0, 11.0, 12.0, 13.0,
    20.0, 21.0, 22.0, 23.0,
    30.0, 31.0, 32.0, 33.0,
];
        
let keys: Vec<Key<_, _>>;
for (c, altitude) in Iterator::zip(coordinates.iter(), alti_array.iter()) {
    keys.push(Key::new(c, altitude, Interpolation::Linear));
}
let spline = Spline::from_vec(keys);

assert_eq!(00.0, spline.clamped_sample(Vector2::new(0.0, 0.0)));
assert_eq!(33.0, spline.clamped_sample(Vector2::new(3.0, 0.3)));

assert_eq!(11.5, spline.clamped_sample(Vector2::new(1.0, 0.15)));
assert_eq!(16.5, spline.clamped_sample(Vector2::new(1.5, 0.15)));
assert_eq!(21.5, spline.clamped_sample(Vector2::new(2.0, 0.15)));

assert_eq!(16.0, spline.clamped_sample(Vector2::new(1.5, 0.1)));
assert_eq!(16.5, spline.clamped_sample(Vector2::new(1.5, 0.15)));
assert_eq!(17.0, spline.clamped_sample(Vector2::new(1.5, 0.2)));

I have enable cgmath support in my Cargo.toml:

splines = { version = "3.3.0", features = ["std", "impl-cgmath"] }

But I get the following error:

error[E0277]: can't compare `cgmath::vector::Vector2<f64>` with `cgmath::vector::Vector2<f64>`
   --> src/main.rs:216:35
    |
216 |     let spline = Spline::from_vec(keys);
    |                                   ^^^^ no implementation for `cgmath::vector::Vector2<f64> < cgmath::vector::Vector2<f64>` and `cgmath::vector::Vector2<f64> > cgmath::vector::Vector2<f64>`
    |
    = help: the trait `std::cmp::PartialOrd` is not implemented for `cgmath::vector::Vector2<f64>`
    = note: required because of the requirements on the impl of `std::cmp::PartialOrd` for `&cgmath::vector::Vector2<f64>`
    = note: required by `splines::spline::Spline::<T, V>::from_vec`

It feels very strange that cgmath::Vector2 doesn't works out-of-the box. What I am missing?

Well it complains that Vector2 is not ordered, which is correct. Points in 2d space have no natural ordering.

This is what I am going to use for the moment. Thanks Alice.

I agree, but I don't understand how I'm supposed to create a Spline since both constructors requires the key to implement PartialOrd. It should be possible to create Spline from a Vector2, otherwise, why would would it implements the traits Linear and Interpolate when you activate the feature cgmath_impl?

Maybe you can still use the trait methods directly, even if you can't put it in a spline?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.