• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 3929938005

pending completion
3929938005

push

github

GitHub
Merge #713

84930 of 96741 relevant lines covered (87.79%)

79640.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.22
/datatypes/src/raster/raster_tile.rs
1
use super::masked_grid::MaskedGrid;
2
use super::{
3
    grid_or_empty::GridOrEmpty, GeoTransform, GeoTransformAccess, GridBounds, GridIdx2D,
4
    GridIndexAccess, GridShape, GridShape2D, GridShape3D, GridShapeAccess, GridSize, Raster,
5
    TileInformation,
6
};
7
use super::{GridIndexAccessMut, RasterProperties};
8
use crate::primitives::{
9
    SpatialBounded, SpatialPartition2D, SpatialPartitioned, SpatialResolution, TemporalBounded,
10
    TimeInterval,
11
};
12
use crate::raster::Pixel;
13
use crate::util::Result;
14
use serde::{Deserialize, Serialize};
15

16
/// A `RasterTile` is a `BaseTile` of raster data where the data is represented by `GridOrEmpty`.
17
pub type RasterTile<D, T> = BaseTile<GridOrEmpty<D, T>>;
18
/// A `RasterTile2D` is a `BaseTile` of 2-dimensional raster data where the data is represented by `GridOrEmpty`.
19
pub type RasterTile2D<T> = RasterTile<GridShape2D, T>;
20
/// A `RasterTile3D` is a `BaseTile` of 3-dimensional raster data where the data is represented by `GridOrEmpty`.
21
pub type RasterTile3D<T> = RasterTile<GridShape3D, T>;
22

23
/// A `MaterializedRasterTile` is a `BaseTile` of raster data where the data is represented by `Grid`. It implements mutable access to pixels.
24
pub type MaterializedRasterTile<D, T> = BaseTile<MaskedGrid<D, T>>;
25
/// A `MaterializedRasterTile2D` is a 2-dimensional `BaseTile` of raster data where the data is represented by `Grid`. It implements mutable access to pixels.
26
pub type MaterializedRasterTile2D<T> = MaterializedRasterTile<GridShape2D, T>;
27
/// A `MaterializedRasterTile3D` is a 3-dimensional `BaseTile` of raster data where the data is represented by `Grid`. It implements mutable access to pixels.
28
pub type MaterializedRasterTile3D<T> = MaterializedRasterTile<GridShape3D, T>;
29

30
/// A `BaseTile` is the main type used to iterate over tiles of raster data
31
/// The data of the `RasterTile` is stored as `Grid` or `NoDataGrid`. The enum `GridOrEmpty` allows a combination of both.
32
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
725✔
33
#[serde(rename_all = "camelCase")]
34
pub struct BaseTile<G> {
35
    /// The `TimeInterval` where this tile is valid.
36
    pub time: TimeInterval,
37
    /// The tile position is the position of the tile in the gird of tiles with origin at the origin of the global_geo_transform.
38
    /// This is NOT a pixel position inside the tile.
39
    pub tile_position: GridIdx2D,
40
    /// The global geotransform to transform pixels into geographic coordinates
41
    pub global_geo_transform: GeoTransform,
42
    /// The pixels of the tile are stored as `Grid` or, in case they are all no-data as `NoDataGrid`.
43
    /// The enum `GridOrEmpty` allows a combination of both.
44
    pub grid_array: G,
45
    /// Metadata for the `BaseTile`
46
    pub properties: RasterProperties,
47
}
48

49
impl<G> BaseTile<G>
50
where
51
    G: GridSize,
52
{
53
    pub fn tile_offset(&self) -> GridIdx2D {
×
54
        self.tile_position
×
55
    }
×
56

57
    pub fn tile_information(&self) -> TileInformation {
1,636✔
58
        TileInformation::new(
1,636✔
59
            self.tile_position,
1,636✔
60
            [self.grid_array.axis_size_y(), self.grid_array.axis_size_x()].into(),
1,636✔
61
            self.global_geo_transform,
1,636✔
62
        )
1,636✔
63
    }
1,636✔
64

65
    /// Use this geo transform to transform `Coordinate2D` into local grid indices and vice versa.
66
    #[inline]
67
    pub fn tile_geo_transform(&self) -> GeoTransform {
3,348,316✔
68
        let global_upper_left_idx = self.tile_position
3,348,316✔
69
            * [
3,348,316✔
70
                self.grid_array.axis_size_y() as isize,
3,348,316✔
71
                self.grid_array.axis_size_x() as isize,
3,348,316✔
72
            ];
3,348,316✔
73

3,348,316✔
74
        let tile_upper_left_coord = self
3,348,316✔
75
            .global_geo_transform
3,348,316✔
76
            .grid_idx_to_pixel_upper_left_coordinate_2d(global_upper_left_idx);
3,348,316✔
77

3,348,316✔
78
        GeoTransform::new(
3,348,316✔
79
            tile_upper_left_coord,
3,348,316✔
80
            self.global_geo_transform.x_pixel_size(),
3,348,316✔
81
            self.global_geo_transform.y_pixel_size(),
3,348,316✔
82
        )
3,348,316✔
83
    }
3,348,316✔
84

85
    pub fn spatial_resolution(&self) -> SpatialResolution {
2✔
86
        self.global_geo_transform.spatial_resolution()
2✔
87
    }
2✔
88
}
89

90
impl<D, T> BaseTile<GridOrEmpty<D, T>>
91
where
92
    T: Pixel,
93
    D: GridSize + Clone + PartialEq,
94
{
95
    /// create a new `RasterTile`
96
    pub fn new_with_tile_info(
395✔
97
        time: TimeInterval,
395✔
98
        tile_info: TileInformation,
395✔
99
        data: GridOrEmpty<D, T>,
395✔
100
    ) -> Self
395✔
101
    where
395✔
102
        D: GridSize,
395✔
103
    {
395✔
104
        debug_assert_eq!(
105
            tile_info.tile_size_in_pixels.axis_size_x(),
395✔
106
            data.shape_ref().axis_size_x()
395✔
107
        );
108

109
        debug_assert_eq!(
110
            tile_info.tile_size_in_pixels.axis_size_y(),
395✔
111
            data.shape_ref().axis_size_y()
395✔
112
        );
113

114
        debug_assert_eq!(
115
            tile_info.tile_size_in_pixels.number_of_elements(),
395✔
116
            data.shape_ref().number_of_elements()
395✔
117
        );
118

119
        Self {
395✔
120
            time,
395✔
121
            tile_position: tile_info.global_tile_position,
395✔
122
            global_geo_transform: tile_info.global_geo_transform,
395✔
123
            grid_array: data,
395✔
124
            properties: Default::default(),
395✔
125
        }
395✔
126
    }
395✔
127

128
    /// create a new `RasterTile`
129
    pub fn new_with_tile_info_and_properties(
659✔
130
        time: TimeInterval,
659✔
131
        tile_info: TileInformation,
659✔
132
        data: GridOrEmpty<D, T>,
659✔
133
        properties: RasterProperties,
659✔
134
    ) -> Self {
659✔
135
        debug_assert_eq!(
136
            tile_info.tile_size_in_pixels.axis_size_x(),
659✔
137
            data.shape_ref().axis_size_x()
659✔
138
        );
139

140
        debug_assert_eq!(
141
            tile_info.tile_size_in_pixels.axis_size_y(),
659✔
142
            data.shape_ref().axis_size_y()
659✔
143
        );
144

145
        debug_assert_eq!(
146
            tile_info.tile_size_in_pixels.number_of_elements(),
659✔
147
            data.shape_ref().number_of_elements()
659✔
148
        );
149

150
        Self {
659✔
151
            time,
659✔
152
            tile_position: tile_info.global_tile_position,
659✔
153
            global_geo_transform: tile_info.global_geo_transform,
659✔
154
            grid_array: data,
659✔
155
            properties,
659✔
156
        }
659✔
157
    }
659✔
158

159
    /// create a new `RasterTile`
160
    pub fn new(
154,660✔
161
        time: TimeInterval,
154,660✔
162
        tile_position: GridIdx2D,
154,660✔
163
        global_geo_transform: GeoTransform,
154,660✔
164
        data: GridOrEmpty<D, T>,
154,660✔
165
    ) -> Self {
154,660✔
166
        Self {
154,660✔
167
            time,
154,660✔
168
            tile_position,
154,660✔
169
            global_geo_transform,
154,660✔
170
            grid_array: data,
154,660✔
171
            properties: RasterProperties::default(),
154,660✔
172
        }
154,660✔
173
    }
154,660✔
174

175
    /// create a new `RasterTile`
176
    pub fn new_with_properties(
3✔
177
        time: TimeInterval,
3✔
178
        tile_position: GridIdx2D,
3✔
179
        global_geo_transform: GeoTransform,
3✔
180
        data: GridOrEmpty<D, T>,
3✔
181
        properties: RasterProperties,
3✔
182
    ) -> Self {
3✔
183
        Self {
3✔
184
            time,
3✔
185
            tile_position,
3✔
186
            global_geo_transform,
3✔
187
            grid_array: data,
3✔
188
            properties,
3✔
189
        }
3✔
190
    }
3✔
191

192
    /// create a new `RasterTile`
193
    pub fn new_without_offset<G>(
27✔
194
        time: TimeInterval,
27✔
195
        global_geo_transform: GeoTransform,
27✔
196
        data: G,
27✔
197
    ) -> Self
27✔
198
    where
27✔
199
        G: Into<GridOrEmpty<D, T>>,
27✔
200
    {
27✔
201
        Self {
27✔
202
            time,
27✔
203
            tile_position: [0, 0].into(),
27✔
204
            global_geo_transform,
27✔
205
            grid_array: data.into(),
27✔
206
            properties: RasterProperties::default(),
27✔
207
        }
27✔
208
    }
27✔
209

210
    /// Returns true if the grid is a `NoDataGrid`
211
    pub fn is_empty(&self) -> bool {
234✔
212
        self.grid_array.is_empty()
234✔
213
    }
234✔
214

215
    /// Convert the tile into a materialized tile.
216
    pub fn into_materialized_tile(self) -> MaterializedRasterTile<D, T> {
120✔
217
        MaterializedRasterTile {
120✔
218
            grid_array: self.grid_array.into_materialized_masked_grid(),
120✔
219
            time: self.time,
120✔
220
            tile_position: self.tile_position,
120✔
221
            global_geo_transform: self.global_geo_transform,
120✔
222
            properties: self.properties,
120✔
223
        }
120✔
224
    }
120✔
225

226
    pub fn materialize(&mut self) {
×
227
        match self.grid_array {
×
228
            GridOrEmpty::Grid(_) => {}
×
229
            GridOrEmpty::Empty(_) => {
×
230
                self.grid_array = self
×
231
                    .grid_array
×
232
                    .clone()
×
233
                    .into_materialized_masked_grid()
×
234
                    .into();
×
235
            }
×
236
        }
237
    }
×
238
}
239

240
impl<G> TemporalBounded for BaseTile<G> {
241
    fn temporal_bounds(&self) -> TimeInterval {
×
242
        self.time
×
243
    }
×
244
}
245

246
impl<G> SpatialPartitioned for BaseTile<G>
247
where
248
    G: GridSize,
249
{
250
    fn spatial_partition(&self) -> SpatialPartition2D {
202✔
251
        self.tile_information().spatial_partition()
202✔
252
    }
202✔
253
}
254

255
impl<D, T, G> Raster<D, T> for BaseTile<G>
256
where
257
    D: GridSize + GridBounds + Clone,
258
    T: Pixel,
259
    G: GridIndexAccess<D::IndexArray, T>,
260
    Self: SpatialBounded + GridShapeAccess<ShapeArray = D::ShapeArray>,
261
{
262
    type DataContainer = G;
263

264
    fn data_container(&self) -> &G {
×
265
        &self.grid_array
×
266
    }
×
267
}
268

269
impl<T, G, I> GridIndexAccess<Option<T>, I> for BaseTile<G>
270
where
271
    G: GridIndexAccess<Option<T>, I>,
272
    T: Pixel,
273
{
274
    fn get_at_grid_index(&self, grid_index: I) -> Result<Option<T>> {
106✔
275
        self.grid_array.get_at_grid_index(grid_index)
106✔
276
    }
106✔
277

278
    fn get_at_grid_index_unchecked(&self, grid_index: I) -> Option<T> {
34,450,350✔
279
        self.grid_array.get_at_grid_index_unchecked(grid_index)
34,450,350✔
280
    }
34,450,350✔
281
}
282

283
impl<T, G, I> GridIndexAccessMut<Option<T>, I> for BaseTile<G>
284
where
285
    G: GridIndexAccessMut<Option<T>, I>,
286
    T: Pixel,
287
{
288
    fn set_at_grid_index(&mut self, grid_index: I, value: Option<T>) -> Result<()> {
×
289
        self.grid_array.set_at_grid_index(grid_index, value)
×
290
    }
×
291

292
    fn set_at_grid_index_unchecked(&mut self, grid_index: I, value: Option<T>) {
×
293
        self.grid_array
×
294
            .set_at_grid_index_unchecked(grid_index, value);
×
295
    }
×
296
}
297

298
impl<G, A> GridShapeAccess for BaseTile<G>
299
where
300
    G: GridShapeAccess<ShapeArray = A>,
301
    A: AsRef<[usize]> + Into<GridShape<A>>,
302
{
303
    type ShapeArray = A;
304

305
    fn grid_shape_array(&self) -> Self::ShapeArray {
1,137✔
306
        self.grid_array.grid_shape_array()
1,137✔
307
    }
1,137✔
308
}
309

310
impl<G> GeoTransformAccess for BaseTile<G> {
311
    fn geo_transform(&self) -> GeoTransform {
702✔
312
        self.global_geo_transform
702✔
313
    }
702✔
314
}
315

316
impl<D, T> From<MaterializedRasterTile<D, T>> for RasterTile<D, T>
317
where
318
    T: Clone,
319
{
320
    fn from(mat_tile: MaterializedRasterTile<D, T>) -> Self {
80✔
321
        RasterTile {
80✔
322
            grid_array: mat_tile.grid_array.into(),
80✔
323
            global_geo_transform: mat_tile.global_geo_transform,
80✔
324
            tile_position: mat_tile.tile_position,
80✔
325
            time: mat_tile.time,
80✔
326
            properties: mat_tile.properties,
80✔
327
        }
80✔
328
    }
80✔
329
}
330

331
/// Pretty printer for raster tiles with 2D ASCII grids
332
pub fn display_raster_tile_2d<P: Pixel + std::fmt::Debug>(
×
333
    raster_tile_2d: &RasterTile2D<P>,
×
334
) -> impl std::fmt::Debug + '_ {
×
335
    struct DebugTile<'a, P>(&'a RasterTile2D<P>);
×
336

×
337
    impl<P: Pixel> std::fmt::Debug for DebugTile<'_, P> {
×
338
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
339
            let tile = self.0;
×
340
            let mut fmt = f.debug_struct(stringify!(RasterTile2D));
×
341
            fmt.field("time", &tile.time);
×
342
            fmt.field("tile_position", &tile.tile_position);
×
343
            fmt.field("global_geo_transform", &tile.global_geo_transform);
×
344
            fmt.field("properties", &tile.properties);
×
345

×
346
            let grid = if let Some(grid) = tile.grid_array.as_masked_grid() {
×
347
                let values: Vec<String> = grid
×
348
                    .masked_element_ref_iterator()
×
349
                    .map(|v| v.map_or('_'.to_string(), |v| format!("{v:?}")))
×
350
                    .collect();
×
351
                let max_digits = values.iter().map(String::len).max().unwrap_or(0);
×
352

×
353
                let mut s = vec![String::new()];
×
354

×
355
                let last_value_index = values.len() - 1;
×
356
                for (i, value) in values.into_iter().enumerate() {
×
357
                    let str_ref = s.last_mut().unwrap();
×
358

×
359
                    str_ref.push_str(&format!("{value:max_digits$}"));
×
360

×
361
                    let is_new_line = (i + 1) % grid.grid_shape().axis_size_x() == 0;
×
362
                    if is_new_line && i < last_value_index {
×
363
                        s.push(String::new());
×
364
                    } else {
×
365
                        str_ref.push(' ');
×
366
                    }
×
367
                }
×
368

×
369
                s
×
370
            } else {
×
371
                vec!["empty".to_string()]
×
372
            };
×
373

×
374
            fmt.field("grid", &grid);
×
375

×
376
            fmt.finish()
×
377
        }
×
378
    }
×
379

×
380
    DebugTile(raster_tile_2d)
×
381
}
×
382

383
#[cfg(test)]
384
mod tests {
385
    use crate::{primitives::Coordinate2D, util::test::TestDefault};
386

387
    use super::*;
388
    use crate::raster::GridIdx;
389

390
    #[test]
1✔
391
    fn tile_information_new() {
1✔
392
        let ti = TileInformation::new(
1✔
393
            GridIdx([0, 0]),
1✔
394
            GridShape2D::from([100, 100]),
1✔
395
            GeoTransform::test_default(),
1✔
396
        );
1✔
397
        assert_eq!(ti.global_geo_transform, GeoTransform::test_default());
1✔
398
        assert_eq!(ti.global_tile_position, GridIdx([0, 0]));
1✔
399
        assert_eq!(ti.tile_size_in_pixels, GridShape2D::from([100, 100]));
1✔
400
    }
1✔
401

402
    #[test]
1✔
403
    fn tile_information_global_tile_position() {
1✔
404
        let ti = TileInformation::new(
1✔
405
            GridIdx([0, 0]),
1✔
406
            GridShape2D::from([100, 100]),
1✔
407
            GeoTransform::test_default(),
1✔
408
        );
1✔
409
        assert_eq!(ti.global_tile_position(), GridIdx([0, 0]));
1✔
410
    }
1✔
411

412
    #[test]
1✔
413
    fn tile_information_local_upper_left() {
1✔
414
        let ti = TileInformation::new(
1✔
415
            GridIdx([0, 0]),
1✔
416
            GridShape2D::from([100, 100]),
1✔
417
            GeoTransform::test_default(),
1✔
418
        );
1✔
419
        assert_eq!(ti.local_upper_left_pixel_idx(), GridIdx([0, 0]));
1✔
420
    }
1✔
421

422
    #[test]
1✔
423
    fn tile_information_local_lower_left() {
1✔
424
        let ti = TileInformation::new(
1✔
425
            GridIdx([0, 0]),
1✔
426
            GridShape2D::from([100, 100]),
1✔
427
            GeoTransform::test_default(),
1✔
428
        );
1✔
429
        assert_eq!(ti.local_lower_left_pixel_idx(), GridIdx([99, 0]));
1✔
430
    }
1✔
431

432
    #[test]
1✔
433
    fn tile_information_local_upper_right() {
1✔
434
        let ti = TileInformation::new(
1✔
435
            GridIdx([0, 0]),
1✔
436
            GridShape2D::from([100, 100]),
1✔
437
            GeoTransform::test_default(),
1✔
438
        );
1✔
439
        assert_eq!(ti.local_upper_right_pixel_idx(), GridIdx([0, 99]));
1✔
440
    }
1✔
441

442
    #[test]
1✔
443
    fn tile_information_local_lower_right() {
1✔
444
        let ti = TileInformation::new(
1✔
445
            GridIdx([0, 0]),
1✔
446
            GridShape2D::from([100, 100]),
1✔
447
            GeoTransform::test_default(),
1✔
448
        );
1✔
449
        assert_eq!(ti.local_lower_right_pixel_idx(), GridIdx([99, 99]));
1✔
450
    }
1✔
451

452
    #[test]
1✔
453
    fn tile_information_global_upper_left_idx() {
1✔
454
        let ti = TileInformation::new(
1✔
455
            GridIdx([0, 0]),
1✔
456
            GridShape2D::from([100, 100]),
1✔
457
            GeoTransform::test_default(),
1✔
458
        );
1✔
459
        assert_eq!(ti.global_upper_left_pixel_idx(), GridIdx([0, 0]));
1✔
460
    }
1✔
461

462
    #[test]
1✔
463
    fn tile_information_global_upper_left_idx_2_3() {
1✔
464
        let ti = TileInformation::new(
1✔
465
            GridIdx([-2, 3]),
1✔
466
            GridShape2D::from([100, 1000]),
1✔
467
            GeoTransform::test_default(),
1✔
468
        );
1✔
469
        assert_eq!(ti.global_upper_left_pixel_idx(), GridIdx([-200, 3000]));
1✔
470
    }
1✔
471

472
    #[test]
1✔
473
    fn tile_information_global_upper_right_idx() {
1✔
474
        let ti = TileInformation::new(
1✔
475
            GridIdx([0, 0]),
1✔
476
            GridShape2D::from([100, 100]),
1✔
477
            GeoTransform::test_default(),
1✔
478
        );
1✔
479
        assert_eq!(ti.global_upper_right_pixel_idx(), GridIdx([0, 99]));
1✔
480
    }
1✔
481

482
    #[test]
1✔
483
    fn tile_information_global_upper_right_idx_2_3() {
1✔
484
        let ti = TileInformation::new(
1✔
485
            GridIdx([-2, 3]),
1✔
486
            GridShape2D::from([100, 1000]),
1✔
487
            GeoTransform::test_default(),
1✔
488
        );
1✔
489
        assert_eq!(ti.global_upper_right_pixel_idx(), GridIdx([-200, 3999]));
1✔
490
    }
1✔
491

492
    #[test]
1✔
493
    fn tile_information_global_lower_right_idx() {
1✔
494
        let ti = TileInformation::new(
1✔
495
            GridIdx([0, 0]),
1✔
496
            GridShape2D::from([100, 100]),
1✔
497
            GeoTransform::test_default(),
1✔
498
        );
1✔
499
        assert_eq!(ti.global_lower_right_pixel_idx(), GridIdx([99, 99]));
1✔
500
    }
1✔
501

502
    #[test]
1✔
503
    fn tile_information_global_lower_right_idx_2_3() {
1✔
504
        let ti = TileInformation::new(
1✔
505
            GridIdx([-2, 3]),
1✔
506
            GridShape2D::from([100, 1000]),
1✔
507
            GeoTransform::test_default(),
1✔
508
        );
1✔
509
        assert_eq!(ti.global_lower_right_pixel_idx(), GridIdx([-101, 3999]));
1✔
510
    }
1✔
511

512
    #[test]
1✔
513
    fn tile_information_global_lower_left_idx() {
1✔
514
        let ti = TileInformation::new(
1✔
515
            GridIdx([0, 0]),
1✔
516
            GridShape2D::from([100, 100]),
1✔
517
            GeoTransform::test_default(),
1✔
518
        );
1✔
519
        assert_eq!(ti.global_lower_left_pixel_idx(), GridIdx([99, 0]));
1✔
520
    }
1✔
521

522
    #[test]
1✔
523
    fn tile_information_global_lower_left_idx_2_3() {
1✔
524
        let ti = TileInformation::new(
1✔
525
            GridIdx([-2, 3]),
1✔
526
            GridShape2D::from([100, 1000]),
1✔
527
            GeoTransform::test_default(),
1✔
528
        );
1✔
529
        assert_eq!(ti.global_lower_left_pixel_idx(), GridIdx([-101, 3000]));
1✔
530
    }
1✔
531

532
    #[test]
1✔
533
    fn tile_information_local_to_global_idx_0_0() {
1✔
534
        let ti = TileInformation::new(
1✔
535
            GridIdx([0, 0]),
1✔
536
            GridShape2D::from([100, 100]),
1✔
537
            GeoTransform::test_default(),
1✔
538
        );
1✔
539
        assert_eq!(
1✔
540
            ti.local_to_global_pixel_idx(GridIdx([25, 75])),
1✔
541
            GridIdx([25, 75])
1✔
542
        );
1✔
543
    }
1✔
544

545
    #[test]
1✔
546
    fn tile_information_local_to_global_idx_2_3() {
1✔
547
        let ti = TileInformation::new(
1✔
548
            GridIdx([-2, 3]),
1✔
549
            GridShape2D::from([100, 1000]),
1✔
550
            GeoTransform::test_default(),
1✔
551
        );
1✔
552
        assert_eq!(
1✔
553
            ti.local_to_global_pixel_idx(GridIdx([25, 75])),
1✔
554
            GridIdx([-175, 3075])
1✔
555
        );
1✔
556
    }
1✔
557

558
    #[test]
1✔
559
    fn tile_information_spatial_partition() {
1✔
560
        let ti = TileInformation::new(
1✔
561
            GridIdx([-2, 3]),
1✔
562
            GridShape2D::from([100, 1000]),
1✔
563
            GeoTransform::test_default(),
1✔
564
        );
1✔
565
        assert_eq!(
1✔
566
            ti.spatial_partition(),
1✔
567
            SpatialPartition2D::new_unchecked(
1✔
568
                Coordinate2D::new(3000., 200.),
1✔
569
                Coordinate2D::new(4000., 100.)
1✔
570
            )
1✔
571
        );
1✔
572
    }
1✔
573

574
    #[test]
1✔
575
    fn tile_information_spatial_bounds_geotransform() {
1✔
576
        let ti = TileInformation::new(
1✔
577
            GridIdx([2, 3]),
1✔
578
            GridShape2D::from([10, 10]),
1✔
579
            GeoTransform::new_with_coordinate_x_y(-180., 0.1, 90., -0.1),
1✔
580
        );
1✔
581
        assert_eq!(
1✔
582
            ti.spatial_partition(),
1✔
583
            SpatialPartition2D::new_unchecked(
1✔
584
                Coordinate2D::new(-177., 88.),
1✔
585
                Coordinate2D::new(-176., 87.)
1✔
586
            )
1✔
587
        );
1✔
588
    }
1✔
589
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc