1use crate::affine::GeoTransform;
3use serde::{Deserialize, Serialize};
4use std::cmp;
5use std::ops::Mul;
6
7#[derive(Debug, Default, PartialEq, Copy, Clone, Serialize, Deserialize)]
9pub struct Window {
10 pub col_off: isize,
11 pub row_off: isize,
12 pub width: usize,
13 pub height: usize,
14}
15
16impl Window {
17 pub fn new(col_off: isize, row_off: isize, width: usize, height: usize) -> Self {
26 Window {
27 col_off,
28 row_off,
29 width,
30 height,
31 }
32 }
33
34 pub fn toranges(self) -> ((isize, isize), (isize, isize)) {
36 (
37 (self.row_off, self.row_off + self.height as isize),
38 (self.col_off, self.col_off + self.width as isize),
39 )
40 }
41
42 pub fn is_zero(self) -> bool {
44 self.height == 0 || self.width == 0
45 }
46
47 pub fn intersects(&self, other: &Window) -> bool {
49 intersection(&[*self, *other]).is_some()
50 }
51
52 pub fn geotransform(&self, geo: &GeoTransform) -> GeoTransform {
54 let (x, y) = geo * (self.col_off, self.row_off);
55 let c = geo.geo[2];
56 let f = geo.geo[5];
57 &GeoTransform::translation(x - c, y - f) * geo
58 }
59
60 pub fn bounds(&self, geo: &GeoTransform) -> (f64, f64, f64, f64) {
62 let row_min = self.row_off;
63 let row_max = row_min + self.height as isize;
64 let col_min = self.col_off;
65 let col_max = col_min + self.width as isize;
66
67 let (left, bottom) = geo * (col_min, row_max);
68 let (right, top) = geo * (col_max, row_min);
69 (left, top, right, bottom)
70 }
71
72 pub fn bounds_lat_long(
73 &self,
74 spatial_ref_code: i32,
75 geo: &GeoTransform,
76 ) -> (f64, f64, f64, f64) {
77 let spatial_ref =
78 gdal::spatial_ref::SpatialRef::from_epsg(spatial_ref_code as u32).unwrap();
79 let wgs84_crs = gdal::spatial_ref::SpatialRef::from_epsg(4326).unwrap();
80 let vertex_trans =
81 gdal::spatial_ref::CoordTransform::new(&spatial_ref, &wgs84_crs).unwrap();
82 let (left, top, right, bottom) = self.bounds(geo);
83 let mut xs = [left, right];
84 let mut ys = [top, bottom];
85 let mut zs = [0.0f64; 2];
86 vertex_trans
87 .transform_coords(&mut xs, &mut ys, &mut zs)
88 .unwrap();
89 (xs[0], ys[0], xs[1], ys[1])
90 }
91
92 }
111
112impl Mul<f64> for Window {
113 type Output = Window;
114
115 fn mul(self, rhs: f64) -> Window {
116 let extended_width = (self.width as f64 * rhs).ceil() as isize;
117 let extended_height = (self.height as f64 * rhs).ceil() as isize;
118 let col_shift = (extended_width - self.width as isize) / 2;
119 let row_shift = (extended_width - self.width as isize) / 2;
120 Window::new(
121 self.col_off - col_shift,
122 self.row_off - row_shift,
123 extended_width as usize,
124 extended_height as usize,
125 )
126 }
127}
128
129fn intersection2(w0: Window, w1: Window) -> Window {
135 if w0.is_zero() || w1.is_zero() {
136 return Window::default();
137 }
138
139 let v0 = cmp::max(w0.col_off, w1.col_off);
140 let v1 = cmp::min(
141 w0.col_off + w0.width as isize,
142 w1.col_off + w1.width as isize,
143 );
144 if v0 >= v1 {
145 return Window::default();
146 }
147
148 let h0 = cmp::max(w0.row_off, w1.row_off);
149 let h1 = cmp::min(
150 w0.row_off + w0.height as isize,
151 w1.row_off + w1.height as isize,
152 );
153 if h0 >= h1 {
154 return Window::default();
155 }
156
157 Window {
158 col_off: v0,
159 row_off: h0,
160 width: (v1 - v0) as usize,
161 height: (h1 - h0) as usize,
162 }
163}
164
165pub fn intersection(windows: &[Window]) -> Option<Window> {
171 match windows.iter().copied().reduce(intersection2) {
172 None => None,
173 Some(w) => {
174 if w == Window::default() {
175 None
176 } else {
177 Some(w)
178 }
179 }
180 }
181}
182
183#[test]
184fn test_intersection2() {
185 let w0 = Window::new(0, 0, 10, 10);
186 let w1 = Window::new(11, 11, 10, 10);
187 assert_eq!(intersection2(w0, w1), Window::new(0, 0, 0, 0));
188
189 let w1 = Window::new(11, 11, 10, 10);
190 let w0 = Window::new(0, 0, 10, 10);
191 assert_eq!(intersection2(w0, w1), Window::new(0, 0, 0, 0));
192
193 let w0 = Window::new(0, 0, 10, 10);
194 let w1 = Window::new(5, 5, 10, 10);
195 assert_eq!(intersection2(w0, w1), Window::new(5, 5, 5, 5));
196
197 let w0 = Window::new(5, 5, 10, 10);
198 let w1 = Window::new(5, 5, 10, 10);
199 assert_eq!(intersection2(w0, w1), Window::new(5, 5, 10, 10));
200
201 let w0 = Window::new(5, 5, 10, 10);
202 let w1 = Window::new(5, 5, 10, 10);
203 assert_eq!(intersection2(w0, w1), Window::new(5, 5, 10, 10));
204
205 let w0 = Window::new(0, 0, 0, 0);
206 let w1 = Window::new(0, 0, 0, 0);
207 assert_eq!(intersection2(w0, w1), Window::new(0, 0, 0, 0));
208}