Skip to main content

science_grid/
grid2d.rs

1use super::constant::INVALID;
2use super::types::Grid;
3use super::util::bilinear;
4use serde::{Deserialize, Serialize};
5// 定义数据结构
6#[derive(Serialize, Deserialize, Debug)]
7pub struct Grid2D {
8    pub epsg: i32,    // 格网地理坐标系
9    pub start_x: f64, // 格网起始经纬度,通常是左上角或左下角
10    pub start_y: f64,
11    end_x: f64,
12    end_y: f64,
13    pub res_x: f64,
14    pub res_y: f64,
15    pub width: usize,
16    pub height: usize,
17    pub datas: Vec<f64>,
18}
19impl Grid for Grid2D {
20    fn get_end_x(&self) -> f64 {
21        self.end_x
22    }
23    fn get_end_y(&self) -> f64 {
24        self.end_y
25    }
26}
27impl Grid2D {
28    pub fn new(
29        start_x: f64,
30        start_y: f64,
31        epsg: i32,
32        res_x: f64,
33        res_y: f64,
34        width: usize,
35        height: usize,
36        datas: Vec<f64>,
37    ) -> Grid2D {
38        // 校验datas长度是否等于宽高
39        if datas.len() != width * height {
40            panic!("2D格网datas长度与元数据的width*height不匹配!");
41        }
42        let end_x = start_x + res_x * (width as f64);
43        let end_y = start_y + res_y * (height as f64);
44        Grid2D {
45            epsg,
46            start_x,
47            start_y,
48            end_x,
49            end_y,
50            res_x,
51            res_y,
52            width,
53            height,
54            datas,
55        }
56    }
57    // 任意经纬度,返回格网数值
58    // 内置双线性插值取值
59    pub fn get_val(&self, x: f64, y: f64) -> f64 {
60        let _min_y = self.start_y.min(self.get_end_y());
61        let _max_y = self.start_y.max(self.get_end_y());
62        if x < self.start_x || x > self.get_end_x() || y < _min_y || y > _max_y {
63            INVALID
64        } else {
65            // 双线性插值
66            // 计算点所在的起始行列号,相对起始点的百分比
67            let float_row = (y - self.start_y) / self.res_y;
68            let float_column = (x - self.start_x) / self.res_x;
69            let start_row = float_row.floor() as usize;
70            let start_column = float_column.floor() as usize;
71            let left_scale_factor = float_column.fract();
72            let top_scale_factor = float_row.fract();
73
74            let mut end_row = start_row + 1;
75            let mut end_column = start_column + 1;
76            if end_row >= self.height {
77                end_row = start_row;
78            }
79            if end_column >= self.width {
80                end_column = start_column;
81            }
82            let lt_index = start_row * self.width + start_column;
83            let rt_index = start_row * self.width + end_column;
84            let lb_index = end_row * self.width + start_column;
85            let rb_index = end_row * self.width + end_column;
86            let lt_wal = self.datas[lt_index];
87            let rt_val = self.datas[rt_index];
88            let lb_val = self.datas[lb_index];
89            let rb_val = self.datas[rb_index];
90            let val = bilinear(
91                lt_wal,
92                rt_val,
93                lb_val,
94                rb_val,
95                left_scale_factor,
96                top_scale_factor,
97            );
98            val
99        }
100    }
101}