Skip to main content

wxy_domain/
affine.rs

1//! Affine transforms in GDAL geotransform order.
2
3/// `[x0, dx, rx, y0, ry, dy]`, as GDAL and vaster order them:
4///
5/// ```text
6/// x = x0 + col * dx + row * rx
7/// y = y0 + col * ry + row * dy
8/// ```
9///
10/// `(col, row)` are continuous index coordinates (0 is the outer edge of
11/// the first cell). Rotation and shear terms (`rx`, `ry`) are allowed.
12#[derive(Debug, Clone, Copy, PartialEq)]
13pub struct Affine(pub [f64; 6]);
14
15impl Affine {
16    /// From an extent `[xmin, xmax, ymin, ymax]` and dimension
17    /// `[ncol, nrow]`, north up (row 0 at `ymax`).
18    pub fn from_extent(extent: [f64; 4], dim: [usize; 2]) -> Self {
19        Affine(vaster::extent_dim_to_gt(&extent, &dim))
20    }
21
22    /// The extent `[xmin, xmax, ymin, ymax]` covered by `dim` cells, for an
23    /// axis-aligned transform.
24    pub fn extent(&self, dim: [usize; 2]) -> [f64; 4] {
25        vaster::gt_to_extent(&self.0, &dim)
26    }
27
28    pub fn forward(&self, col: f64, row: f64) -> (f64, f64) {
29        let g = &self.0;
30        (
31            g[0] + col * g[1] + row * g[2],
32            g[3] + col * g[4] + row * g[5],
33        )
34    }
35
36    pub fn inverse(&self) -> Option<Affine> {
37        vaster::inv_geotransform(&self.0).map(Affine)
38    }
39
40    pub fn is_axis_aligned(&self) -> bool {
41        self.0[2] == 0.0 && self.0[4] == 0.0
42    }
43}