1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
//! # `CellMap` implementation

// ------------------------------------------------------------------------------------------------
// IMPORTS
// ------------------------------------------------------------------------------------------------

use std::{
    marker::PhantomData,
    ops::{Index, IndexMut},
    usize,
};

use nalgebra::{Affine2, Point2, Vector2};
use ndarray::{s, Array2};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

use crate::{
    cell_map_file::CellMapFile,
    extensions::Point2Ext,
    iterators::{
        layerers::Many,
        slicers::{Cells, Line, Windows},
        CellMapIter, CellMapIterMut,
    },
    map_metadata::CellMapMetadata,
    Error, Layer,
};

// ------------------------------------------------------------------------------------------------
// STRUCTS
// ------------------------------------------------------------------------------------------------

/// Provides a many-layer 2D map of cellular data.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(
    try_from = "CellMapFile<L, T>",
    into = "CellMapFile<L, T>",
    bound = "T: Clone + Serialize + DeserializeOwned, L: Serialize + DeserializeOwned"
)]
pub struct CellMap<L, T>
where
    L: Layer,
{
    /// Stores each layer in the map as an [`ndarray::Array2<T>`].
    ///
    /// TODO:
    /// When constgenerics is stabilised would be good to make this an array of `L::NUM_LAYERS`, to
    /// avoid the vec allocation.
    pub(crate) data: Vec<Array2<T>>,

    /// Metadata associated with this map.
    pub(crate) metadata: CellMapMetadata,

    /// The original parameters supplied to `CellMap::new()`.
    pub(crate) params: CellMapParams,

    layer_type: PhantomData<L>,
}

/// Contains parameters required to construct a [`CellMap`]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct CellMapParams {
    /// The size (resolution) of each cell in the map, in parent frame coordinates.
    ///
    /// # Default
    ///
    /// The default value is `[1.0, 1.0]`.
    pub cell_size: Vector2<f64>,

    /// The number of cells in the `x` and `y` directions.
    ///
    /// # Default
    ///
    /// The default value is [`Bounds::empty()`].
    pub cell_bounds: Bounds,

    /// The rotation of the map's Z axis about the parent Z axis in radians.
    ///
    /// # Default
    ///
    /// The default value is `0.0`.
    pub rotation_in_parent_rad: f64,

    /// The position of the origin of the map in the parent frame, in parent frame units.
    ///
    /// # Default
    ///
    /// The default value is `[0.0, 0.0]`.
    pub position_in_parent: Vector2<f64>,

    /// The precision to use when determining cell boundaries.
    ///
    /// This precision factor allows us to account for times when a cell position should fit into a
    /// particular cell index, but due to floating point rounding does not. For example take a map
    /// with a `cell_size = [0.1, 0.1]`, the cell index of the position `[0.7, 0.1]` should be `[7,
    /// 1`], however the positions floating point index would be calculated as `[6.999999999999998,
    /// 0.9999999999999999]`, which if `floor()`ed to fit into a `usize` would give the incorrect
    /// index `[6, 0]`.
    ///
    /// When calculating cell index we therefore `floor` the floating point index unless it is
    /// within `cell_size * cell_boundary_precision`, in which case we round up to the next cell.
    /// Mutliplying by `cell_size` allows this value to be independent of the scale of the map.
    ///
    /// # Default
    ///
    /// The default value is `1e-10`.
    pub cell_boundary_precision: f64,
}

/// Rectangular bounds describing the number of cells in each direction of the map.
///
/// These bounds are a half-open range, i.e. satisfied in the ranges:
///  - $x_0 <= x < x_1$
///  - $y_0 <= y < y_1$
// NOTE: Range isn't uses since it's not Copy
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub struct Bounds {
    /// The bounds on the x axis, in the format (min, max),
    pub x: (isize, isize),

    /// The bounds on the y axis, in the format (min, max),
    pub y: (isize, isize),
}

// ------------------------------------------------------------------------------------------------
// IMPLS
// ------------------------------------------------------------------------------------------------

impl<L, T> CellMap<L, T>
where
    L: Layer,
{
    /// Creates a new map from the given data.
    ///
    /// If data is the wrong shape or has the wrong number of layers this function will return an
    /// error.
    pub fn new_from_data(params: CellMapParams, data: Vec<Array2<T>>) -> Result<Self, Error> {
        if data.len() != L::NUM_LAYERS {
            return Err(Error::WrongNumberOfLayers(L::NUM_LAYERS, data.len()));
        }

        if !data.is_empty() {
            let layer_cells = (data[0].shape()[0], data[0].shape()[1]);

            if layer_cells != params.cell_bounds.get_shape() {
                return Err(Error::LayerWrongShape(
                    layer_cells,
                    params.cell_bounds.get_shape(),
                ));
            }
        }

        Ok(Self {
            data,
            metadata: params.into(),
            params,
            layer_type: PhantomData,
        })
    }

    /// Returns the size of the cells in the map.
    pub fn cell_size(&self) -> Vector2<f64> {
        self.metadata.cell_size
    }

    /// Returns the number of cells in each direction of the map.
    pub fn num_cells(&self) -> Vector2<usize> {
        self.metadata.num_cells
    }

    /// Returns the bounds of this map
    pub fn cell_bounds(&self) -> Bounds {
        self.metadata.cell_bounds
    }

    /// Returns the parameters used to build this map.
    pub fn params(&self) -> CellMapParams {
        self.params
    }

    /// Gets the [`nalgebra::Affine2<f64>`] transformation between the map frame and the parent
    /// frame.
    pub fn to_parent(&self) -> Affine2<f64> {
        self.metadata.to_parent
    }

    /// Moves this map relative to a new position and rotation relative to the parent frame.
    ///
    /// **Note:** This doesn't move the data relative to the map origin, the indexes into the map
    /// remain the same, but the position of each cell in the map will change.
    pub fn move_map(&mut self, position_in_parent: Vector2<f64>, rotation_in_parent_rad: f64) {
        // Recalculate the map's to_parent affine
        self.metadata.to_parent = CellMapMetadata::calc_to_parent(
            position_in_parent,
            rotation_in_parent_rad,
            self.metadata.cell_size,
        );

        // Update the parameter values
        self.params.position_in_parent = position_in_parent;
        self.params.rotation_in_parent_rad = rotation_in_parent_rad;
    }

    /// Returns whether or not the given index is inside the map.
    pub fn index_in_map(&self, index: Point2<usize>) -> bool {
        self.metadata.is_in_map(index)
    }

    /// Returns whether or not the given parent-relative position is inside the map.
    pub fn position_in_map(&self, position: Point2<f64>) -> bool {
        self.index(position).is_some()
    }

    /// Get a reference to the value at the given layer and index. Returns `None` if the index is
    /// outside the bounds of the map.
    pub fn get(&self, layer: L, index: Point2<usize>) -> Option<&T> {
        if self.index_in_map(index) {
            Some(&self[(layer, index)])
        } else {
            None
        }
    }

    /// Get a reference to the value at the given layer and index, without checking the bounds of
    /// the map.
    ///
    /// # Safety
    ///
    /// This function will panic if `index` is outside the map.
    pub unsafe fn get_unchecked(&self, layer: L, index: Point2<usize>) -> &T {
        &self[(layer, index)]
    }

    /// Get a mutable reference to the value at the given layer and index. Returns `None` if the
    /// index is outside the bounds of the map.
    pub fn get_mut(&mut self, layer: L, index: Point2<usize>) -> Option<&mut T> {
        if self.index_in_map(index) {
            Some(&mut self[(layer, index)])
        } else {
            None
        }
    }

    /// Get a mutable reference to the value at the given layer and index, without checking the
    /// bounds of the map.
    ///
    /// # Safety
    ///
    /// This function will panic if `index` is outside the map.
    pub unsafe fn get_mut_unchecked(&mut self, layer: L, index: Point2<usize>) -> &mut T {
        &mut self[(layer, index)]
    }

    /// Set the given layer and index in the map to the given value. Returns an [`Error`] if the
    /// index was outside the map.
    pub fn set(&mut self, layer: L, index: Point2<usize>, value: T) -> Result<(), Error> {
        if self.index_in_map(index) {
            self[(layer, index)] = value;
            Ok(())
        } else {
            Err(Error::IndexOutsideMap(index))
        }
    }

    /// Set the given layer and index in the map to the given value, without checking if index is
    /// the map.
    ///
    /// # Safety
    ///
    /// This function will panic if `index` is outside the map
    pub unsafe fn set_unchecked(&mut self, layer: L, index: Point2<usize>, value: T) {
        self[(layer, index)] = value;
    }

    /// Returns the position in the parent frame of the centre of the given cell index.
    ///
    /// Returns `None` if the given `index` is not inside the map.
    pub fn position(&self, index: Point2<usize>) -> Option<Point2<f64>> {
        self.metadata.position(index)
    }

    /// Returns the position in the parent frame of the centre of the given cell index, without
    /// checking that the `index` is inside the map.
    ///
    /// # Safety
    ///
    /// This method won't panic if `index` is outside the map, but it's result can't be guaranteed
    /// to be a position in the map.
    pub fn position_unchecked(&self, index: Point2<usize>) -> Point2<f64> {
        self.metadata.position_unchecked(index)
    }

    /// Get the cell index of the given poisition.
    ///
    /// Returns `None` if the given `position` is not inside the map.
    pub fn index(&self, position: Point2<f64>) -> Option<Point2<usize>> {
        self.metadata.index(position)
    }

    /// Get the cell index of the given poisition, without checking that the position is inside the
    /// map.
    ///
    /// # Safety
    ///
    /// This function will not panic if `position` is outside the map, but use of the result to
    /// index into the map is not guaranteed to be safe. It is possible for this function to return
    /// a negative index value, which would indicate that the cell is outside the map.
    pub unsafe fn index_unchecked(&self, position: Point2<f64>) -> Point2<isize> {
        self.metadata.index_unchecked(position)
    }

    /// Returns an iterator over each cell in all layers of the map.
    pub fn iter(&self) -> CellMapIter<'_, L, T, Many<L>, Cells> {
        CellMapIter::<'_, L, T, Many<L>, Cells>::new_cells(self)
    }

    /// Returns a mutable iterator over each cell in all layers of the map.
    pub fn iter_mut(&mut self) -> CellMapIterMut<'_, L, T, Many<L>, Cells> {
        CellMapIterMut::<'_, L, T, Many<L>, Cells>::new_cells(self)
    }

    /// Returns an iterator over windows of cells in the map.
    ///
    /// The `semi_width` is half the size of the window in the x and y axes, not including
    /// the central cell. E.g. to have a window which is in total 5x5, the `semi_window_size` needs
    /// to be `Vector2::new(2, 2)`.
    pub fn window_iter(
        &self,
        semi_width: Vector2<usize>,
    ) -> Result<CellMapIter<'_, L, T, Many<L>, Windows>, Error> {
        CellMapIter::<'_, L, T, Many<L>, Windows>::new_windows(self, semi_width)
    }

    /// Returns a mutable iterator over windows of cells in the map.
    ///
    /// The `semi_width` is half the size of the window in the x and y axes, not including
    /// the central cell. E.g. to have a window which is in total 5x5, the `semi_window_size` needs
    /// to be `Vector2::new(2, 2)`.
    pub fn window_iter_mut(
        &mut self,
        semi_width: Vector2<usize>,
    ) -> Result<CellMapIterMut<'_, L, T, Many<L>, Windows>, Error> {
        CellMapIterMut::<'_, L, T, Many<L>, Windows>::new_windows(self, semi_width)
    }

    /// Returns an iterator over cells along the line joining `start_position` and
    /// `end_position`, which are expressed as positions in the map's parent frame.
    pub fn line_iter(
        &self,
        start_position: Point2<f64>,
        end_position: Point2<f64>,
    ) -> Result<CellMapIter<'_, L, T, Many<L>, Line>, Error> {
        CellMapIter::<'_, L, T, Many<L>, Line>::new_line(self, start_position, end_position)
    }

    /// Returns a mutable iterator over cells along the line joining `start_position` and
    /// `end_position`, which are expressed as positions in the map's parent frame.
    pub fn line_iter_mut(
        &mut self,
        start_position: Point2<f64>,
        end_position: Point2<f64>,
    ) -> Result<CellMapIterMut<'_, L, T, Many<L>, Line>, Error> {
        CellMapIterMut::<'_, L, T, Many<L>, Line>::new_line(self, start_position, end_position)
    }
}

impl<L, T> CellMap<L, T>
where
    L: Layer + Serialize,
    T: Clone + Serialize,
{
    /// Builds a new [`CellMapFile`] from the given map, which can be serialised or deserialised
    /// using serde.
    pub fn to_cell_map_file(&self) -> CellMapFile<L, T> {
        CellMapFile::new(self)
    }

    /// Writes the map to the given path as a JSON file.
    #[cfg(feature = "json")]
    pub fn write_json<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), Error> {
        let map_file = CellMapFile::new(&self);
        map_file.write_json(path)
    }
}

impl<L, T> CellMap<L, T>
where
    L: Layer + DeserializeOwned,
    T: DeserializeOwned,
{
    /// Loads a map stored in JSON format at the given path.
    #[cfg(feature = "json")]
    pub fn from_json<P: AsRef<std::path::Path>>(path: P) -> Result<Self, Error> {
        let map_file = CellMapFile::from_json(path)?;
        map_file.into_cell_map()
    }
}

impl<L, T> CellMap<L, T>
where
    L: Layer,
    T: Clone,
{
    /// Creates a new [`CellMap`] from the given params, filling each cell with `elem`.
    pub fn new_from_elem(params: CellMapParams, elem: T) -> Self {
        let data = vec![Array2::from_elem(params.cell_bounds.get_shape(), elem); L::NUM_LAYERS];

        Self {
            data,
            metadata: params.into(),
            params,
            layer_type: PhantomData,
        }
    }
}

impl<L, T> CellMap<L, T>
where
    L: Layer,
    T: Default + Clone,
{
    /// Creates a new [`CellMap`] from the given params, filling each cell with `T::default()`.
    pub fn new(params: CellMapParams) -> Self {
        let data =
            vec![Array2::from_elem(params.cell_bounds.get_shape(), T::default()); L::NUM_LAYERS];

        Self {
            data,
            metadata: params.into(),
            params,
            layer_type: PhantomData,
        }
    }

    /// Resizes the map into the new bounds, filling any newly added cells with `T::default()`.
    ///
    /// Any cells that are in the map currently, which would be outside the new map, are removed.
    // NOTE: It doesn't seem possible to resize an ndarray in place, so we have to allocate a new
    // one.
    pub fn resize(&mut self, new_bounds: Bounds) {
        // Allocate new data
        let mut data = vec![Array2::from_elem(new_bounds.get_shape(), T::default()); L::NUM_LAYERS];

        // Get the slice describing the position of the old map inside the new map, based on the
        // bounds. If there's no intersection then we can skip this step
        if let Some(old_in_new) = new_bounds.get_slice_of_other(&self.metadata.cell_bounds) {
            // Get the slice of new relative to old. Unwrap is ok sice we already know there's an
            // intersection.
            let new_in_old = self
                .metadata
                .cell_bounds
                .get_slice_of_other(&new_bounds)
                .unwrap();
            for (new, old) in data.iter_mut().zip(self.data.iter()) {
                new.slice_mut(s![
                    old_in_new.y.0..old_in_new.y.1,
                    old_in_new.x.0..old_in_new.x.1
                ])
                .assign(&old.slice(s![
                    new_in_old.y.0..new_in_old.y.1,
                    new_in_old.x.0..new_in_old.x.1
                ]));
            }
        }

        self.data = data;
        self.metadata.cell_bounds = new_bounds;
        self.params.cell_bounds = new_bounds;
        self.metadata.num_cells = new_bounds.get_num_cells();
    }

    /// Merge `other` into self, resizing `self` so that `other` will be fully included in the map.
    ///
    /// Both maps should belong to the same parent frame, and `other.cell_size <= self.cell_size`.
    /// For `other`s that have larger cells than `self` you should implement your own merge functon
    /// based on this one that could for example use 2D linear interpolation.
    ///
    /// `func` is responsible for actually merging data in both `self` and `other` into a single
    /// new value in `self`. The first argument is the value of the cell in `self`, while the
    /// second argument will be the values from cells in `other` whose centres lie within the cell
    /// in `self`.
    pub fn merge<F: Fn(&T, &[T]) -> T>(&mut self, other: &CellMap<L, T>, func: F) {
        // First get the bounds of `other` wrt `self`, which we have to do by accounting for the
        // potential different alignment of `other` wrt `parent`. We do this by getting the corner
        // points, transforming from `other` to `parent`, then from `parent` to `self`. We have to
        // transform all corner points because rotation may lead to the corners being in different
        // positions than when aligned to `other`.
        let other_bounds = other.cell_bounds();
        let corners_in_other = vec![
            Point2::new(other_bounds.x.0, other_bounds.y.0).cast(),
            Point2::new(other_bounds.x.1, other_bounds.y.0).cast() + Vector2::new(1.0, 0.0),
            Point2::new(other_bounds.x.0, other_bounds.y.1).cast() + Vector2::new(0.0, 1.0),
            Point2::new(other_bounds.x.1, other_bounds.y.1).cast() + Vector2::new(1.0, 1.0),
        ];
        let corners_in_parent: Vec<Point2<f64>> = corners_in_other
            .iter()
            .map(|c| other.to_parent().transform_point(c))
            .collect();
        let other_bl_parent = Point2::new(
            corners_in_parent
                .iter()
                .min_by_key(|c| c.x.floor() as isize)
                .unwrap()
                .x
                .floor(),
            corners_in_parent
                .iter()
                .min_by_key(|c| c.y.floor() as isize)
                .unwrap()
                .y
                .floor(),
        );
        let other_ur_parent = Point2::new(
            corners_in_parent
                .iter()
                .max_by_key(|c| c.x.ceil() as isize)
                .unwrap()
                .x
                .ceil(),
            corners_in_parent
                .iter()
                .max_by_key(|c| c.y.ceil() as isize)
                .unwrap()
                .y
                .ceil(),
        );
        let other_in_self =
            Bounds::from_corner_positions(&self.metadata, other_bl_parent, other_ur_parent);
        let store_offset = Vector2::new(
            other_in_self.x.0.clamp(0, self.num_cells().x as isize) as usize,
            other_in_self.y.0.clamp(0, self.num_cells().y as isize) as usize,
        );

        // Calculate the union of both bounds
        let new_bounds = self.cell_bounds().union(&other_in_self);

        // Resize self
        self.resize(new_bounds);

        // Get the index offset to go from an index into self to the 2D storage array (see store)
        let store_slice_in_new = if let Some(slice) = new_bounds.get_slice_of_other(&other_in_self)
        {
            slice
        } else {
            unreachable!("Other was not inside self's new bounds");
        };

        // For each layer in the map
        for layer in L::all() {
            // Create a new array of size other_in_self, which will hold a copy of all items in
            // other which fall into each cell in self.
            let mut store: Array2<Vec<T>> = Array2::default(other_in_self.get_shape());

            // For each cell in other get its position in parent, convert that to a cell index in
            // self, and add that cell's value to the store
            for ((_, pos), val) in other.iter().layer(layer.clone()).positioned() {
                // The index of pos in self
                if let Some(idx) = self.index(pos) {
                    // Get the index into the store array by subtracting the store offset
                    let store_idx = (idx.cast() - store_offset).map(|e| e as usize);

                    // Mutate the store vector by pushing val into it
                    if let Some(vec) = store.get_mut(store_idx.as_array2_index()) {
                        vec.push(val.clone());
                    } else {
                        unreachable!("Store index {} was invalid", store_idx);
                    }
                } else {
                    // Point was outside the map, this shouldn't happen
                    unreachable!("Point in other ({}) was outside self during merge", pos);
                }
            }

            // Iterate over the store and self, calling the merge function with the value in self
            // and the values in the store
            for (self_val, store_vec) in self.data[layer.to_index()]
                .slice_mut(s![
                    store_slice_in_new.y.0..store_slice_in_new.y.1,
                    store_slice_in_new.x.0..store_slice_in_new.x.1,
                ])
                .iter_mut()
                .zip(store.iter())
            {
                *self_val = func(self_val, store_vec.as_slice());
            }
        }
    }
}

impl<L, T> Index<L> for CellMap<L, T>
where
    L: Layer,
{
    type Output = Array2<T>;

    fn index(&self, index: L) -> &Self::Output {
        &self.data[index.to_index()]
    }
}

impl<L, T> IndexMut<L> for CellMap<L, T>
where
    L: Layer,
{
    fn index_mut(&mut self, index: L) -> &mut Self::Output {
        &mut self.data[index.to_index()]
    }
}

impl<L, T> Index<(L, Point2<usize>)> for CellMap<L, T>
where
    L: Layer,
{
    type Output = T;

    fn index(&self, index: (L, Point2<usize>)) -> &Self::Output {
        &self[index.0][(index.1.y, index.1.x)]
    }
}

impl<L, T> IndexMut<(L, Point2<usize>)> for CellMap<L, T>
where
    L: Layer,
{
    fn index_mut(&mut self, index: (L, Point2<usize>)) -> &mut Self::Output {
        &mut self[index.0][(index.1.y, index.1.x)]
    }
}

impl Default for CellMapParams {
    fn default() -> Self {
        Self {
            cell_size: Vector2::new(1.0, 1.0),
            cell_bounds: Bounds::empty(),
            cell_boundary_precision: 1e-10,
            rotation_in_parent_rad: 0.0,
            position_in_parent: Vector2::zeros(),
        }
    }
}

impl Bounds {
    /// Creates a new empty (zero sized) bound
    pub fn empty() -> Self {
        Self {
            x: (0, 0),
            y: (0, 0),
        }
    }

    /// Returns if the bounds are valid or not, i.e. if the minimum is larger than the maximum.
    pub fn is_valid(&self) -> bool {
        self.x.0 <= self.x.1 && self.y.0 <= self.y.1
    }

    /// Creates a new bound from the given max and min cell indices in the x and y axes.
    ///
    /// Must satisfy:
    ///  - $x_0 <= x_1$
    ///  - $y_0 <= y_1$
    pub fn new(x: (isize, isize), y: (isize, isize)) -> Result<Self, Error> {
        let bounds = Self { x, y };

        if bounds.is_valid() {
            Ok(bounds)
        } else {
            Err(Error::InvalidBounds(bounds))
        }
    }

    /// Creates a new bound from the given opposing corners of the a rectangle.
    ///
    /// If the corners do not satisfy `all(bottom_left <= upper_right)` the bounds will be invalid
    /// and an error is returned.
    pub fn from_corners(
        bottom_left: Point2<isize>,
        upper_right: Point2<isize>,
    ) -> Result<Self, Error> {
        let bounds = Self {
            x: (bottom_left.x, upper_right.x),
            y: (bottom_left.y, upper_right.y),
        };

        if bounds.is_valid() {
            Ok(bounds)
        } else {
            Err(Error::InvalidBounds(bounds))
        }
    }

    /// Creates a new bound from the given opposing corners of the a rectangle, but the corners do
    /// not have to be sorted in bottom_left, upper_right order.
    ///
    /// This function will automatically decide which points are provided such that the bounds will
    /// be valid.
    pub fn from_corners_unsorted(a: Point2<isize>, b: Point2<isize>) -> Self {
        Self {
            x: (a.x.min(b.x), a.x.max(b.x)),
            y: (a.y.min(b.y), a.y.max(b.y)),
        }
    }

    /// Creates a new bound from the given corner positions, which do not have to be in any order.
    ///
    /// The metadata parameter will be used to map from parent frame position into a map frame.
    pub(crate) fn from_corner_positions(
        metadata: &CellMapMetadata,
        a: Point2<f64>,
        b: Point2<f64>,
    ) -> Self {
        // Get the map-rel cell of each point
        let cell_a = metadata.get_cell(a);
        let cell_b = metadata.get_cell(b);

        // Build the bounds
        Self::from_corners_unsorted(cell_a, cell_b)
    }

    /// Converts this bounds into a pair of corners, the bottom left and upper right corners
    /// respectively.
    pub fn as_corners(&self) -> (Point2<isize>, Point2<isize>) {
        (
            Point2::new(self.x.0, self.y.0),
            Point2::new(self.x.1, self.y.1),
        )
    }

    /// Checks if the given point is inside the bounds
    pub fn contains(&self, point: Point2<isize>) -> bool {
        self.x.0 <= point.x && point.x < self.x.1 && self.y.0 <= point.y && point.y < self.y.1
    }

    /// Gets the value of the point as an index into an array bounded by this `Bounds`.
    ///
    /// If the point is outside the bounds `None` is returned
    pub fn get_index(&self, point: Point2<isize>) -> Option<Point2<usize>> {
        if self.contains(point) {
            let unchecked = unsafe { self.get_index_unchecked(point) };

            // Have already checked that the point is inside the bounds, no need to check again
            Some(Point2::new(unchecked.x as usize, unchecked.y as usize))
        } else {
            None
        }
    }

    /// Gets the value of the point as an index into an array bounded by this `Bounds`.
    ///
    /// # Safety
    ///
    /// This function will not panic if `point` is outside the map, but use of the result to
    /// index into the map is not guaranteed to be safe. It is possible for this function to return
    /// a negative index value, which would indicate that the cell is outside the map.
    pub unsafe fn get_index_unchecked(&self, point: Point2<isize>) -> Point2<isize> {
        Point2::new(point.x - self.x.0, point.y - self.y.0)
    }

    /// Gets the shape of this rectangle in a format that `ndarray` will accept.
    ///
    /// NOTE: shape order is (y, x), not (x, y).
    pub fn get_shape(&self) -> (usize, usize) {
        (
            (self.y.1 - self.y.0) as usize,
            (self.x.1 - self.x.0) as usize,
        )
    }

    /// Gets the number of cells as a vector.
    pub fn get_num_cells(&self) -> Vector2<usize> {
        let shape = self.get_shape();
        Vector2::new(shape.1, shape.0)
    }

    /// Gets the intersection of self with other, returning `None` if the two do not intersect.
    pub fn intersect(&self, other: &Bounds) -> Option<Bounds> {
        Bounds::new(
            (self.x.0.max(other.x.0), self.x.1.min(other.x.1)),
            (self.y.0.max(other.y.0), self.y.1.min(other.y.1)),
        )
        .ok()
    }

    /// Get the union of `self` with `other`, effectively this is the axis aligned bounding box of
    /// `self` and `other`.
    ///
    /// If both bounds are empty this bound will be empty.
    pub fn union(&self, other: &Bounds) -> Bounds {
        Bounds::new(
            (self.x.0.min(other.x.0), self.x.1.max(other.x.1)),
            (self.y.0.min(other.y.0), self.y.1.max(other.y.1)),
        )
        .unwrap_or_default()
    }

    /// Gets the slice of other within self, cropping other so it fits within self.
    ///
    /// Note that slices are a pair of (min, max) half-open bounds that describe the slice into an
    /// array, i.e. they are indices.
    pub fn get_slice_of_other(&self, other: &Bounds) -> Option<Vector2<(usize, usize)>> {
        // First get intersection of the two bounds in the origin frame
        let intersect = self.intersect(other)?;

        // Rebase the intersection to be a slice relative to the start of self, i.e. subtract the
        // min bound on each axis from both min and max of the intersection
        Some(Vector2::new(
            (
                (intersect.x.0 - self.x.0) as usize,
                (intersect.x.1 - self.x.0) as usize,
            ),
            (
                (intersect.y.0 - self.y.0) as usize,
                (intersect.y.1 - self.y.0) as usize,
            ),
        ))
    }
}

impl Default for Bounds {
    fn default() -> Self {
        Self::empty()
    }
}