surface_grid/
sphere.rs

1//! A module containing grids wrapped around spheres.
2
3use std::{f64::consts::PI, ops::{Index, IndexMut}, vec, fmt::Debug};
4
5use itertools::Itertools;
6use rayon::prelude::*;
7use static_array::HeapArray2D;
8
9use crate::{GridPoint, SurfaceGrid};
10
11/// A point on a spherical grid.
12pub trait SpherePoint : GridPoint {
13    /// Gets a sphere point for the specified geographic coordinates.
14    ///
15    /// - `latitude` - The latitude of the point in radians where 0 is the equator.
16    /// - `longitude` - The longitude of the point in radians.
17    fn from_geographic(latitude: f64, longitude: f64) -> Self;
18
19    /// Gets the latitude of this point.
20    fn latitude(&self) -> f64;
21
22    /// Gets the longitude of this point.
23    fn longitude(&self) -> f64;
24    
25    /// Returns a coordinate containing the latitude and longitude of this point.
26    /// This returns a point with the X component being the longitude and the Y component being the
27    /// latitude.
28    fn sphere_coordinates(&self) -> (f64, f64) {
29        (self.longitude(), self.latitude())
30    }
31}
32
33/// A grid for a sphere based on the equirectangular projection.
34///
35/// # Type Parameters
36/// - `T` - The type of data that the grid holds.
37///
38/// # Constant Parameters
39/// - `W` - The width of the grid.
40/// - `H` - The height of the grid.
41#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
42pub struct RectangleSphereGrid<T, const W: usize, const H: usize> {
43    /// The data held in this grid.
44    data: HeapArray2D<T, W, H>,
45}
46
47impl <T, const W: usize, const H: usize> SurfaceGrid<T> for RectangleSphereGrid<T, W, H> {
48    type Point = RectangleSpherePoint<W, H>;
49
50    fn from_fn<F: FnMut(&Self::Point) -> T>(mut f: F) -> Self {
51        Self {
52            data: HeapArray2D::from_fn(|y, x| {
53                let point = RectangleSpherePoint::new(x as u32, y as u32);
54
55                f(&point)
56            })
57        }
58    }
59
60    fn from_fn_par<F: Fn(&Self::Point) -> T + Send + Sync>(f: F) -> Self where T: Send + Sync {
61        Self {
62            data: HeapArray2D::from_fn_par(|y, x| {
63                let point = RectangleSpherePoint::new(x as u32, y as u32);
64
65                f(&point)
66            })
67        }
68    }
69
70    fn set_from_fn<F: FnMut(&Self::Point) -> T>(&mut self, mut f: F) {
71        (0..H).cartesian_product(0..W)
72            .map(|(y, x)| RectangleSpherePoint::new(x as u32, y as u32))
73            .for_each(|point| self[point] = f(&point))
74    }
75
76    fn set_from_fn_par<F: Fn(&Self::Point) -> T + Send + Sync>(&mut self, f: F) where T: Send + Sync {
77        self.data.iter_mut().enumerate().par_bridge().for_each(|(y, subarray)| {
78            for x in 0..W {
79                let point = RectangleSpherePoint::new(x as u32, y as u32);
80
81                subarray[x] = f(&point);
82            }
83        })
84    }
85
86    fn iter<'a>(&'a self) -> impl Iterator<Item = (RectangleSpherePoint<W, H>, &'a T)> where T: 'a {
87        (0..H).cartesian_product(0..W)
88            .map(|(y, x)| (RectangleSpherePoint::new(x as u32, y as u32), &self.data[y][x]))
89    }
90
91    fn par_iter<'a>(&'a self) -> impl ParallelIterator<Item = (Self::Point, &'a T)> where T: 'a + Send + Sync {
92        (0..H).cartesian_product(0..W)
93            .par_bridge()
94            .map(|(y, x)| (RectangleSpherePoint::new(x as u32, y as u32), &self.data[y][x]))
95    }
96
97    fn points(&self) -> impl Iterator<Item = Self::Point> {
98        (0..H).cartesian_product(0..W)
99            .map(|(y, x)| RectangleSpherePoint::new(x as u32, y as u32))
100    }
101
102    fn par_points(&self) -> impl ParallelIterator<Item = Self::Point> {
103        (0..H).cartesian_product(0..W)
104            .par_bridge()
105            .map(|(y, x)| RectangleSpherePoint::new(x as u32, y as u32))
106    }
107
108    fn for_each(&mut self, mut f: impl FnMut(&mut T)) {
109        (0..H).cartesian_product(0..W)
110            .for_each(|(y, x)| f(&mut self.data[y][x]))
111    }
112
113    fn for_each_with_position(&mut self, mut f: impl FnMut(&Self::Point, &mut T)) {
114        (0..H).cartesian_product(0..W)
115            .for_each(|(y, x)| f(&RectangleSpherePoint::new(x as u32, y as u32), &mut self.data[y][x]))
116    }
117
118    fn par_for_each(&mut self, f: impl Fn(&mut T) + Sync) where T: Send + Sync {
119        self.data.iter_mut().par_bridge().for_each(|subarray| {
120            for x in 0..W {
121                f(&mut subarray[x]);
122            }
123        })
124    }
125
126    fn par_for_each_with_position(&mut self, f: impl Fn(&Self::Point, &mut T) + Sync) where T: Send + Sync {
127        self.data.iter_mut().enumerate().par_bridge().for_each(|(y, subarray)| {
128            for x in 0..W {
129                let point = RectangleSpherePoint::new(x as u32, y as u32);
130
131                f(&point, &mut subarray[x]);
132            }
133        })
134    }
135}
136
137impl <T, const W: usize, const H: usize> Index<RectangleSpherePoint<W, H>> for RectangleSphereGrid<T, W, H> {
138    type Output = T;
139
140    fn index(&self, index: RectangleSpherePoint<W, H>) -> &Self::Output {
141        &self.data[index.y as usize][index.x as usize]
142    }
143}
144
145impl <T, const W: usize, const H: usize> IndexMut<RectangleSpherePoint<W, H>> for RectangleSphereGrid<T, W, H> {
146    fn index_mut(&mut self, index: RectangleSpherePoint<W, H>) -> &mut Self::Output {
147        &mut self.data[index.y as usize][index.x as usize]
148    }
149}
150
151impl <T, const W: usize, const H: usize> IntoIterator for RectangleSphereGrid<T, W, H> {
152    type Item = (RectangleSpherePoint<W, H>, T);
153
154    type IntoIter = vec::IntoIter<Self::Item>;
155
156    fn into_iter(self) -> Self::IntoIter {
157        let data: Vec<_> = self.data.into_iter()
158            .enumerate()
159            .flat_map(|(y, subarray)| subarray.into_iter()
160                      .enumerate()
161                      .map(move |(x, value)| (RectangleSpherePoint::new(x as u32, y as u32), value))
162                      )
163            .collect();
164
165        data.into_iter()
166    }
167}
168
169/// A point on a `RectangleSphereGrid`.
170///
171/// # Constant Parameters
172/// - `W` - The width of the grid.
173/// - `H` - The height of the grid.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
175pub struct RectangleSpherePoint<const W: usize, const H: usize> {
176    /// The X position in the grid.
177    x: u32,
178    /// The Y position in the grid.
179    y: u32,
180}
181
182impl <const W: usize, const H: usize> RectangleSpherePoint<W, H> {
183    fn new(x: u32, y: u32) -> Self {
184        let x = (x + y / H as u32).rem_euclid(W as u32);
185        let y = y.rem_euclid(H as u32);
186
187        Self {
188            x,
189            y
190        }
191    }
192}
193
194impl <const W: usize, const H: usize> GridPoint for RectangleSpherePoint<W, H> {
195    fn up(&self) -> Self {
196        if self.x >= W as u32 / 2 {
197            if self.y == H as u32 - 1 {
198                Self {
199                    x: (self.x + W as u32 / 2).rem_euclid(W as u32),
200                    y: H as u32 - 1,
201                }
202            } else {
203                Self {
204                    x: self.x,
205                    y: self.y + 1,
206                }
207            }
208        } else {
209            if self.y == 0 {
210                Self {
211                    x: (self.x + W as u32 / 2).rem_euclid(W as u32),
212                    y: 0,
213                }
214            } else {
215                Self {
216                    x: self.x,
217                    y: self.y - 1,
218                }
219            }
220        }
221    }
222
223    fn down(&self) -> Self {
224        if self.x < W as u32 / 2 {
225            if self.y == H as u32 - 1 {
226                Self {
227                    x: (self.x + W as u32 / 2).rem_euclid(W as u32),
228                    y: H as u32 - 1,
229                }
230            } else {
231                Self {
232                    x: self.x,
233                    y: self.y + 1,
234                }
235            }
236        } else {
237            if self.y == 0 {
238                Self {
239                    x: (self.x + W as u32 / 2).rem_euclid(W as u32),
240                    y: 0,
241                }
242            } else {
243                Self {
244                    x: self.x,
245                    y: self.y - 1,
246                }
247            }
248        }
249    }
250
251    fn left(&self) -> Self {
252        Self {
253            x: (self.x as i32 - 1).rem_euclid(W as i32) as u32,
254            y: self.y
255        }
256    }
257
258    fn right(&self) -> Self {
259        Self {
260            x: (self.x + 1).rem_euclid(W as u32),
261            y: self.y
262        }
263    }
264
265    fn position(&self, scale: f64) -> (f64, f64, f64) {
266        let (long, lat) = self.sphere_coordinates();
267
268        let y = scale * lat.sin();
269        let radius = scale * lat.cos();
270
271        let x = radius * long.sin();
272        let z = radius * long.cos();
273
274        (x, y, z)
275    }
276}
277
278impl <const W: usize, const H: usize> SpherePoint for RectangleSpherePoint<W, H> {
279    fn from_geographic(latitude: f64, longitude: f64) -> Self {
280        let latitude = -latitude;
281
282        let x = ((longitude / (PI * 2.0) * W as f64) as i32).rem_euclid(W as i32) as u32;
283        let y = (latitude + PI / 2.0) / PI;
284
285        let y = ((2 * (y.ceil() as i32).rem_euclid(2) - 1)
286            * ((y * H as f64) as i32).rem_euclid(H as i32)
287            + H as i32 * (y.floor() as i32).rem_euclid(2)) as u32;
288
289        let y = if y == H as u32 {
290            H as u32 - 1
291        } else {
292            y
293        };
294
295        Self {
296            x, y
297        }
298    }
299    
300    fn latitude(&self) -> f64 {
301        -(self.y as f64 / H as f64 * PI - PI / 2.0)
302    }
303
304    fn longitude(&self) -> f64 {
305        self.x as f64 / W as f64 * PI * 2.0
306    }
307}
308
309/// A grid that wraps a cube around a sphere in order to determine grid positions.
310///
311/// # Type Parameters.
312/// - `T` - The type of element stored in each grid cell.
313///
314/// # Constant Parameters
315/// - `S` - The size of each side of each face.
316#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
317pub struct CubeSphereGrid<T, const S: usize> {
318    top: HeapArray2D<T, S, S>,
319    left: HeapArray2D<T, S, S>,
320    front: HeapArray2D<T, S, S>,
321    right: HeapArray2D<T, S, S>,
322    back: HeapArray2D<T, S, S>,
323    bottom: HeapArray2D<T, S, S>,
324}
325
326impl <T: Debug, const S: usize> SurfaceGrid<T> for CubeSphereGrid<T, S> {
327    type Point = CubeSpherePoint<S>;
328
329    fn from_fn<F: FnMut(&Self::Point) -> T>(mut f: F) -> Self {
330        Self {
331            top: HeapArray2D::from_fn(|y, x| f(&CubeSpherePoint::new(CubeFace::Top, x as u16, y as u16))),
332            left: HeapArray2D::from_fn(|y, x| f(&CubeSpherePoint::new(CubeFace::Left, x as u16, y as u16))),
333            front: HeapArray2D::from_fn(|y, x| f(&CubeSpherePoint::new(CubeFace::Front, x as u16, y as u16))),
334            right: HeapArray2D::from_fn(|y, x| f(&CubeSpherePoint::new(CubeFace::Right, x as u16, y as u16))),
335            back: HeapArray2D::from_fn(|y, x| f(&CubeSpherePoint::new(CubeFace::Back, x as u16, y as u16))),
336            bottom: HeapArray2D::from_fn(|y, x| f(&CubeSpherePoint::new(CubeFace::Bottom, x as u16, y as u16))),
337        }
338    }
339
340    fn from_fn_par<F: Fn(&Self::Point) -> T + Send + Sync>(f: F) -> Self where T: Send + Sync {
341        Self {
342            top: HeapArray2D::from_fn_par(|y, x| f(&CubeSpherePoint::new(CubeFace::Top, x as u16, y as u16))),
343            left: HeapArray2D::from_fn_par(|y, x| f(&CubeSpherePoint::new(CubeFace::Left, x as u16, y as u16))),
344            front: HeapArray2D::from_fn_par(|y, x| f(&CubeSpherePoint::new(CubeFace::Front, x as u16, y as u16))),
345            right: HeapArray2D::from_fn_par(|y, x| f(&CubeSpherePoint::new(CubeFace::Right, x as u16, y as u16))),
346            back: HeapArray2D::from_fn_par(|y, x| f(&CubeSpherePoint::new(CubeFace::Back, x as u16, y as u16))),
347            bottom: HeapArray2D::from_fn_par(|y, x| f(&CubeSpherePoint::new(CubeFace::Bottom, x as u16, y as u16))),
348        }
349    }
350
351    fn set_from_fn<F: FnMut(&Self::Point) -> T>(&mut self, mut f: F) {
352        [
353            CubeFace::Top,
354            CubeFace::Left,
355            CubeFace::Front,
356            CubeFace::Right,
357            CubeFace::Back,
358            CubeFace::Bottom,
359        ].into_iter()
360            .cartesian_product(0..S)
361            .cartesian_product(0..S)
362            .map(|((face, x), y)| CubeSpherePoint::new(face, x as u16, y as u16))
363            .map(|point| (point, f(&point)))
364            .for_each(|(point, value)| self[point] = value)
365    }
366
367    fn set_from_fn_par<F: Fn(&Self::Point) -> T + Send + Sync>(&mut self, f: F) where T: Send + Sync {
368        for face in [
369            CubeFace::Top,
370            CubeFace::Left,
371            CubeFace::Front,
372            CubeFace::Right,
373            CubeFace::Back,
374            CubeFace::Bottom,
375        ] {
376            match face {
377                CubeFace::Front => &mut self.front,
378                CubeFace::Back => &mut self.back,
379                CubeFace::Left => &mut self.left,
380                CubeFace::Right => &mut self.right,
381                CubeFace::Top => &mut self.top,
382                CubeFace::Bottom => &mut self.bottom,
383            }.iter_mut().enumerate().par_bridge().for_each(|(y, subarray)| for x in 0..S {
384                let point = CubeSpherePoint::new(face, x as u16, y as u16);
385
386                subarray[x] = f(&point);
387            });
388        }
389    }
390
391    fn iter<'a>(&'a self) -> impl Iterator<Item = (Self::Point, &'a T)> where T: 'a {
392        self.points()
393            .map(|point| (point, &self[point]))
394    }
395
396    fn par_iter<'a>(&'a self) -> impl ParallelIterator<Item = (Self::Point, &'a T)> where T: 'a + Send + Sync {
397        self.par_points()
398            .map(|point| (point, &self[point]))
399    }
400
401    fn points(&self) -> impl Iterator<Item = Self::Point> {
402        [
403            CubeFace::Top,
404            CubeFace::Left,
405            CubeFace::Front,
406            CubeFace::Right,
407            CubeFace::Back,
408            CubeFace::Bottom,
409        ].into_iter()
410            .cartesian_product(0..S)
411            .cartesian_product(0..S)
412            .map(|((face, x), y)| CubeSpherePoint::new(face, x as u16, y as u16))
413    }
414
415    fn par_points(&self) -> impl ParallelIterator<Item = Self::Point> {
416        [
417            CubeFace::Top,
418            CubeFace::Left,
419            CubeFace::Front,
420            CubeFace::Right,
421            CubeFace::Back,
422            CubeFace::Bottom,
423        ].into_iter()
424            .cartesian_product(0..S)
425            .cartesian_product(0..S)
426            .par_bridge()
427            .map(|((face, x), y)| CubeSpherePoint::new(face, x as u16, y as u16))
428    }
429
430    fn for_each(&mut self, mut f: impl FnMut(&mut T)) {
431        (0..S).cartesian_product(0..S)
432            .for_each(|(x, y)| {
433                f(&mut self.front[y][x]);
434                f(&mut self.back[y][x]);
435                f(&mut self.left[y][x]);
436                f(&mut self.right[y][x]);
437                f(&mut self.top[y][x]);
438                f(&mut self.bottom[y][x]);
439            })
440    }
441
442    fn for_each_with_position(&mut self, mut f: impl FnMut(&Self::Point, &mut T)) {
443        [
444            CubeFace::Top,
445            CubeFace::Left,
446            CubeFace::Front,
447            CubeFace::Right,
448            CubeFace::Back,
449            CubeFace::Bottom,
450        ].into_iter()
451            .cartesian_product(0..S)
452            .cartesian_product(0..S)
453            .for_each(|((face, x), y)| f(&CubeSpherePoint::new(face, x as u16, y as u16), match face {
454                CubeFace::Top => &mut self.top[y][x],
455                CubeFace::Left => &mut self.left[y][x],
456                CubeFace::Front => &mut self.front[y][x],
457                CubeFace::Right => &mut self.right[y][x],
458                CubeFace::Back => &mut self.back[y][x],
459                CubeFace::Bottom => &mut self.bottom[y][x],
460            }))
461    }
462    
463    fn par_for_each(&mut self, f: impl Fn(&mut T) + Sync) where T: Send + Sync{
464        for face in [
465            CubeFace::Top,
466            CubeFace::Left,
467            CubeFace::Front,
468            CubeFace::Right,
469            CubeFace::Back,
470            CubeFace::Bottom,
471        ] {
472            match face {
473                CubeFace::Front => &mut self.front,
474                CubeFace::Back => &mut self.back,
475                CubeFace::Left => &mut self.left,
476                CubeFace::Right => &mut self.right,
477                CubeFace::Top => &mut self.top,
478                CubeFace::Bottom => &mut self.bottom,
479            }.iter_mut().par_bridge().for_each(|subarray| for x in 0..S {
480                f(&mut subarray[x]);
481            });
482        }
483    }
484
485    fn par_for_each_with_position(&mut self, f: impl Fn(&Self::Point, &mut T) + Sync) where T: Send + Sync {
486        for face in [
487            CubeFace::Top,
488            CubeFace::Left,
489            CubeFace::Front,
490            CubeFace::Right,
491            CubeFace::Back,
492            CubeFace::Bottom,
493        ] {
494            match face {
495                CubeFace::Front => &mut self.front,
496                CubeFace::Back => &mut self.back,
497                CubeFace::Left => &mut self.left,
498                CubeFace::Right => &mut self.right,
499                CubeFace::Top => &mut self.top,
500                CubeFace::Bottom => &mut self.bottom,
501            }.iter_mut().enumerate().par_bridge().for_each(|(y, subarray)| for x in 0..S {
502                let point = CubeSpherePoint::new(face, x as u16, y as u16);
503
504                f(&point, &mut subarray[x]);
505            });
506        }
507    }
508}
509
510impl <T, const S: usize> Index<CubeSpherePoint<S>> for CubeSphereGrid<T, S> {
511    type Output = T;
512
513    fn index(&self, index: CubeSpherePoint<S>) -> &Self::Output {
514        match index.face {
515            CubeFace::Front => &self.front[index.y as usize][index.x as usize],
516            CubeFace::Back => &self.back[index.y as usize][index.x as usize],
517            CubeFace::Left => &self.left[index.y as usize][index.x as usize],
518            CubeFace::Right => &self.right[index.y as usize][index.x as usize],
519            CubeFace::Top => &self.top[index.y as usize][index.x as usize],
520            CubeFace::Bottom => &self.bottom[index.y as usize][index.x as usize],
521        }
522    }
523}
524
525impl <T, const S: usize> IndexMut<CubeSpherePoint<S>> for CubeSphereGrid<T, S> {
526    fn index_mut(&mut self, index: CubeSpherePoint<S>) -> &mut Self::Output {
527        match index.face {
528            CubeFace::Front => &mut self.front[index.y as usize][index.x as usize],
529            CubeFace::Back => &mut self.back[index.y as usize][index.x as usize],
530            CubeFace::Left => &mut self.left[index.y as usize][index.x as usize],
531            CubeFace::Right => &mut self.right[index.y as usize][index.x as usize],
532            CubeFace::Top => &mut self.top[index.y as usize][index.x as usize],
533            CubeFace::Bottom => &mut self.bottom[index.y as usize][index.x as usize],
534        }
535    }
536}
537
538impl <T, const S: usize> IntoIterator for CubeSphereGrid<T, S> {
539    type Item = (CubeSpherePoint<S>, T);
540
541    type IntoIter = vec::IntoIter<Self::Item>;
542
543    fn into_iter(self) -> Self::IntoIter {
544        let mut data: Vec<_> = self.top.into_iter()
545            .enumerate()
546            .flat_map(|(y, subarray)| subarray.into_iter()
547                        .enumerate()
548                        .map(move |(x, value)| (CubeSpherePoint::new(CubeFace::Top, x as u16, y as u16), value))
549                      )
550            .collect();
551
552        data.extend(self.left.into_iter()
553                    .enumerate()
554                    .flat_map(|(y, subarray)| subarray.into_iter()
555                              .enumerate()
556                              .map(move |(x, value)| (CubeSpherePoint::new(CubeFace::Left, x as u16, y as u16), value))
557                              ));
558        data.extend(self.front.into_iter()
559                    .enumerate()
560                    .flat_map(|(y, subarray)| subarray.into_iter()
561                              .enumerate()
562                              .map(move |(x, value)| (CubeSpherePoint::new(CubeFace::Front, x as u16, y as u16), value))
563                              ));
564        data.extend(self.right.into_iter()
565                    .enumerate()
566                    .flat_map(|(y, subarray)| subarray.into_iter()
567                              .enumerate()
568                              .map(move |(x, value)| (CubeSpherePoint::new(CubeFace::Right, x as u16, y as u16), value))
569                              ));
570        data.extend(self.back.into_iter()
571                    .enumerate()
572                    .flat_map(|(y, subarray)| subarray.into_iter()
573                              .enumerate()
574                              .map(move |(x, value)| (CubeSpherePoint::new(CubeFace::Back, x as u16, y as u16), value))
575                              ));
576        data.extend(self.bottom.into_iter()
577                    .enumerate()
578                    .flat_map(|(y, subarray)| subarray.into_iter()
579                              .enumerate()
580                              .map(move |(x, value)| (CubeSpherePoint::new(CubeFace::Bottom, x as u16, y as u16), value))
581                              ));
582
583        data.into_iter()
584    }
585}
586
587/// A point on a `CubeSphereGrid`.
588///
589/// # Constant Parameters
590/// - `S` - The size of each side of each face.
591#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
592pub struct CubeSpherePoint<const S: usize> {
593    face: CubeFace,
594    x: u16,
595    y: u16,
596}
597
598impl <const S: usize> CubeSpherePoint<S> {
599    /// Creates a new `CubeSpherePoint`.
600    ///
601    /// - `face` - The face on which the point lies.
602    /// - `x` - The X position on the face.
603    /// - `y` - The Y position on the face.
604    fn new(face: CubeFace, x: u16, y: u16) -> Self {
605        Self {
606            face,
607            // Clamp to account for floating point rounding error.
608            x: x.clamp(0, S as u16 - 1),
609            y: y.clamp(0, S as u16 - 1)
610        }
611    }
612}
613
614impl <const S: usize> GridPoint for CubeSpherePoint<S> {
615    fn up(&self) -> Self {
616        match self.face {
617            CubeFace::Front => if self.y == 0 {
618                Self {
619                    face: CubeFace::Top,
620                    x: self.x,
621                    y: S as u16 - 1,
622                }
623            } else {
624                Self {
625                    face: CubeFace::Front,
626                    x: self.x,
627                    y: self.y - 1,
628                }
629            },
630            CubeFace::Back => if self.y == 0 {
631                Self {
632                    face: CubeFace::Bottom,
633                    x: self.x,
634                    y: S as u16 - 1,
635                }
636            } else {
637                Self {
638                    face: CubeFace::Back,
639                    x: self.x,
640                    y: self.y - 1,
641                }
642            },
643            CubeFace::Left => if self.y == 0 {
644                Self {
645                    face: CubeFace::Top,
646                    x: 0,
647                    y: self.x
648                }
649            } else {
650                Self {
651                    face: CubeFace::Left,
652                    x: self.x,
653                    y: self.y - 1,
654                }
655            },
656            CubeFace::Right => if self.y == 0 {
657                Self {
658                    face: CubeFace::Top,
659                    x: S as u16 - 1,
660                    y: self.x
661                }
662            } else {
663                Self {
664                    face: CubeFace::Right,
665                    x: self.x,
666                    y: self.y - 1,
667                }
668            },
669            CubeFace::Top => if self.y == 0 {
670                Self {
671                    face: CubeFace::Back,
672                    x: self.x,
673                    y: S as u16 - 1,
674                }
675            } else {
676                Self {
677                    face: CubeFace::Top,
678                    x: self.x,
679                    y: self.y - 1,
680                }
681            },
682            CubeFace::Bottom => if self.y == 0 {
683                Self {
684                    face: CubeFace::Front,
685                    x: self.x,
686                    y: S as u16 - 1,
687                }
688            } else {
689                Self {
690                    face: CubeFace::Bottom,
691                    x: self.x,
692                    y: self.y - 1,
693                }
694            },
695        }
696    }
697
698    fn down(&self) -> Self {
699        match self.face {
700            CubeFace::Front => if self.y == S as u16 - 1 {
701                Self {
702                    face: CubeFace::Bottom,
703                    x: self.x,
704                    y: 0,
705                }
706            } else {
707                Self {
708                    face: CubeFace::Front,
709                    x: self.x,
710                    y: self.y + 1,
711                }
712            },
713            CubeFace::Back => if self.y == S as u16 - 1 {
714                Self {
715                    face: CubeFace::Top,
716                    x: self.x,
717                    y: 0,
718                }
719            } else {
720                Self {
721                    face: CubeFace::Back,
722                    x: self.x,
723                    y: self.y + 1,
724                }
725            },
726            CubeFace::Left => if self.y == S as u16 - 1 {
727                Self {
728                    face: CubeFace::Bottom,
729                    x: 0,
730                    y: self.x
731                }
732            } else {
733                Self {
734                    face: CubeFace::Left,
735                    x: self.x,
736                    y: self.y + 1,
737                }
738            },
739            CubeFace::Right => if self.y == S as u16 - 1 {
740                Self {
741                    face: CubeFace::Bottom,
742                    x: 0,
743                    y: self.x
744                }
745            } else {
746                Self {
747                    face: CubeFace::Right,
748                    x: self.x,
749                    y: self.y + 1,
750                }
751            },
752            CubeFace::Top => if self.y == S as u16 - 1 {
753                Self {
754                    face: CubeFace::Front,
755                    x: self.x,
756                    y: 0,
757                }
758            } else {
759                Self {
760                    face: CubeFace::Top,
761                    x: self.x,
762                    y: self.y + 1,
763                }
764            },
765            CubeFace::Bottom => if self.y == S as u16 - 1 {
766                Self {
767                    face: CubeFace::Back,
768                    x: self.x,
769                    y: 0,
770                }
771            } else {
772                Self {
773                    face: CubeFace::Bottom,
774                    x: self.x,
775                    y: self.y + 1,
776                }
777            },
778        }
779    }
780
781    fn left(&self) -> Self {
782        match self.face {
783            CubeFace::Front => if self.x == 0 {
784                Self {
785                    face: CubeFace::Left,
786                    x: S as u16 - 1,
787                    y: self.y
788                }
789            } else {
790                Self {
791                    face: CubeFace::Front,
792                    x: self.x - 1,
793                    y: self.y
794                }
795            },
796            CubeFace::Back => if self.x == S as u16 - 1 {
797                Self {
798                    face: CubeFace::Right,
799                    x: S as u16 - 1,
800                    y: self.y
801                }
802            } else {
803                Self {
804                    face: CubeFace::Back,
805                    x: self.x + 1,
806                    y: self.y
807                }
808            },
809            CubeFace::Left => if self.x == 0 {
810                Self {
811                    face: CubeFace::Back,
812                    x: 0,
813                    y: self.y,
814                }
815            } else {
816                Self {
817                    face: CubeFace::Left,
818                    x: self.x - 1,
819                    y: self.y
820                }
821            },
822            CubeFace::Right => if self.x == 0 {
823                Self {
824                    face: CubeFace::Front,
825                    x: S as u16 - 1,
826                    y: self.y
827                }
828            } else {
829                Self {
830                    face: CubeFace::Right,
831                    x: self.x - 1,
832                    y: self.y,
833                }
834            },
835            CubeFace::Top => if self.x == 0 {
836                Self {
837                    face: CubeFace::Left,
838                    x: self.y,
839                    y: 0,
840                }
841            } else {
842                Self {
843                    face: CubeFace::Top,
844                    x: self.x - 1,
845                    y: self.y
846                }
847            },
848            CubeFace::Bottom => if self.x == 0 {
849                Self {
850                    face: CubeFace::Left,
851                    x: self.y,
852                    y: S as u16 - 1,
853                }
854            } else {
855                Self {
856                    face: CubeFace::Bottom,
857                    x: self.x - 1,
858                    y: self.y
859                }
860            },
861        }
862    }
863
864    fn right(&self) -> Self {
865        match self.face {
866            CubeFace::Front => if self.x == S as u16 - 1 {
867                Self {
868                    face: CubeFace::Right,
869                    x: 0,
870                    y: self.y
871                }
872            } else {
873                Self {
874                    face: CubeFace::Front,
875                    x: self.x + 1,
876                    y: self.y
877                }
878            },
879            CubeFace::Back => if self.x == 0 {
880                Self {
881                    face: CubeFace::Left,
882                    x: 0,
883                    y: self.y
884                }
885            } else {
886                Self {
887                    face: CubeFace::Back,
888                    x: self.x - 1,
889                    y: self.y
890                }
891            },
892            CubeFace::Left => if self.x == S as u16 - 1 {
893                Self {
894                    face: CubeFace::Front,
895                    x: 0,
896                    y: self.y,
897                }
898            } else {
899                Self {
900                    face: CubeFace::Left,
901                    x: self.x + 1,
902                    y: self.y
903                }
904            },
905            CubeFace::Right => if self.x == S as u16 - 1 {
906                Self {
907                    face: CubeFace::Back,
908                    x: S as u16 - 1,
909                    y: self.y
910                }
911            } else {
912                Self {
913                    face: CubeFace::Right,
914                    x: self.x + 1,
915                    y: self.y,
916                }
917            },
918            CubeFace::Top => if self.x == S as u16 - 1{
919                Self {
920                    face: CubeFace::Right,
921                    x: self.y,
922                    y: 0,
923                }
924            } else {
925                Self {
926                    face: CubeFace::Top,
927                    x: self.x + 1,
928                    y: self.y
929                }
930            },
931            CubeFace::Bottom => if self.x == S as u16 - 1 {
932                Self {
933                    face: CubeFace::Right,
934                    x: self.y,
935                    y: S as u16 - 1,
936                }
937            } else {
938                Self {
939                    face: CubeFace::Bottom,
940                    x: self.x + 1,
941                    y: self.y
942                }
943            },
944        }
945    }
946
947    fn position(&self, scale: f64) -> (f64, f64, f64) {
948        let x = self.x as f64;
949        let y = self.y as f64;
950
951        let (x, y, z) = match self.face {
952            CubeFace::Front => (x * 2.0 - S as f64, y * 2.0 - S as f64, S as f64),
953            CubeFace::Back => (x * 2.0 - S as f64, -y * 2.0 + S as f64, -(S as f64)),
954            CubeFace::Left => (-(S as f64), y * 2.0 - S as f64, x * 2.0 -(S as f64)),
955            CubeFace::Right => (S as f64, y * 2.0 - S as f64, S as f64 - x * 2.0),
956            CubeFace::Top => (x * 2.0 - S as f64, S as f64, y * 2.0 - S as f64),
957            CubeFace::Bottom => (x * 2.0 - S as f64, -(S as f64), S as f64 - y * 2.0),
958        };
959
960        let length = (x * x + y * y + z * z).sqrt();
961
962        (x / length * scale, y / length * scale, z / length * scale)
963    }
964}
965
966impl <const S: usize> SpherePoint for CubeSpherePoint<S> {
967    fn from_geographic(latitude: f64, longitude: f64) -> Self {
968        let y = latitude.sin();
969
970        let radius = latitude.cos();
971
972        let x = radius * longitude.sin();
973        let z = radius * longitude.cos();
974
975        let longitude = longitude.rem_euclid(2.0 * PI);
976
977        let face = if y > 0.0 {
978            let scale = S as f64 / y;
979
980            let z = z * scale;
981            let x = x * scale;
982            
983            let x2 = (x + S as f64) / 2.0;
984            let y2 = (z + S as f64) / 2.0;
985
986            if (x2 as i32) >= 0 && (x2 as i32) < (S as i32) && (y2 as i32) > 0 && (y2 as i32) < (S as i32) {
987                return CubeSpherePoint::new(CubeFace::Top, x2 as u16, y2 as u16);
988            }
989                
990            if longitude > PI / 4.0 + 3.0 * PI / 2.0 {
991                CubeFace::Front
992            } else if longitude > PI / 4.0 + 2.0 * PI / 2.0 {
993                CubeFace::Left
994            } else if longitude > PI / 4.0 + PI / 2.0 {
995                CubeFace::Back
996            } else if longitude > PI / 4.0 {
997                CubeFace::Right
998            } else {
999                CubeFace::Front
1000            }
1001        } else {
1002            let scale = -(S as f64) / y;
1003
1004            let z = z * scale;
1005            let x = x * scale;
1006            
1007            let x2 = (x + S as f64) / 2.0;
1008            let y2 = (S as f64 - z) / 2.0;
1009
1010            if (x2 as i32) >= 0 && (x2 as i32) < (S as i32) && (y2 as i32) > 0 && (y2 as i32) < (S as i32) {
1011                return CubeSpherePoint::new(CubeFace::Bottom, x2 as u16, y2 as u16);
1012            }
1013            if longitude > PI / 4.0 + 3.0 * PI / 2.0 {
1014                CubeFace::Front
1015            } else if longitude > PI / 4.0 + 2.0 * PI / 2.0 {
1016                CubeFace::Left
1017            } else if longitude > PI / 4.0 + PI / 2.0 {
1018                CubeFace::Back
1019            } else if longitude > PI / 4.0 {
1020                CubeFace::Right
1021            } else {
1022                CubeFace::Front
1023            }
1024        };
1025
1026        match face {
1027            CubeFace::Front => {
1028                let scale = S as f64 / z;
1029
1030                let x2 = (x * scale + S as f64) / 2.0;
1031                let y2 = (y * scale + S as f64) / 2.0;
1032
1033                CubeSpherePoint::new(CubeFace::Front, x2 as u16, y2 as u16)
1034            },
1035            CubeFace::Back => {
1036                let scale = -(S as f64) / z;
1037
1038                let x = x * scale;
1039                let y = y * scale;
1040                
1041                let x2 = (x + S as f64) / 2.0;
1042                let y2 = (y - S as f64) / -2.0;
1043                
1044                CubeSpherePoint::new(CubeFace::Back, x2 as u16, y2 as u16)
1045            },
1046            CubeFace::Left => {
1047                let scale = -(S as f64) / x;
1048
1049                let z = z * scale;
1050                let y = y * scale;
1051
1052                let x2 = (z + S as f64) / 2.0;
1053                let y2 = (y + S as f64) / 2.0;
1054                
1055                CubeSpherePoint::new(CubeFace::Left, x2 as u16, y2 as u16)
1056            },
1057            CubeFace::Right => {
1058                let scale = S as f64 / x;
1059
1060                let z = z * scale;
1061                let y = y * scale;
1062                
1063                let x2 = (S as f64 - z) / 2.0;
1064                let y2 = (y + S as f64) / 2.0;
1065                
1066                CubeSpherePoint::new(CubeFace::Right, x2 as u16, y2 as u16)
1067            },
1068            CubeFace::Top => {
1069                let scale = S as f64 / y;
1070
1071                let z = z * scale;
1072                let x = x * scale;
1073                
1074                let x2 = (x + S as f64) / 2.0;
1075                let y2 = (z + S as f64) / 2.0;
1076                
1077                CubeSpherePoint::new(CubeFace::Top, x2 as u16, y2 as u16)
1078            },
1079            CubeFace::Bottom => {
1080                let scale = -(S as f64) / y;
1081
1082                let z = z * scale;
1083                let x = x * scale;
1084                
1085                let x2 = (x + S as f64) / 2.0;
1086                let y2 = (S as f64 - z) / 2.0;
1087                
1088                CubeSpherePoint::new(CubeFace::Bottom, x2 as u16, y2 as u16)
1089            },
1090        }
1091    }
1092
1093    fn latitude(&self) -> f64 {
1094        let (x, y, z) = self.position(1.0);
1095
1096        let distance = (x * x + z * z).sqrt();
1097
1098        (y / distance).atan()
1099    }
1100
1101    fn longitude(&self) -> f64 {
1102        let (x, _, z) = self.position(1.0);
1103
1104        x.atan2(z).rem_euclid(2.0 * PI)
1105    }
1106}
1107
1108/// A face of a cube.
1109#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1110#[repr(u32)] // For better alignment.
1111enum CubeFace {
1112    Front,
1113    Back,
1114    Left,
1115    Right,
1116    Top,
1117    Bottom,
1118}
1119
1120#[cfg(test)]
1121mod test {
1122    use std::{f64::consts::PI, hint::black_box};
1123
1124    use approx::assert_relative_eq;
1125
1126    use crate::{GridPoint, SurfaceGrid, sphere::{CubeSpherePoint, CubeFace, CubeSphereGrid}};
1127
1128    use super::{RectangleSpherePoint, SpherePoint, RectangleSphereGrid};
1129
1130    #[test]
1131    fn test_rect_point_up_middle() {
1132        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(3, 4);
1133
1134        assert_eq!(RectangleSpherePoint::new(3, 3), point.up());
1135    }
1136    
1137    #[test]
1138    fn test_rect_point_up_top_left() {
1139        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(0, 0);
1140
1141        assert_eq!(RectangleSpherePoint::new(5, 0), point.up());
1142    }
1143    
1144    #[test]
1145    fn test_rect_point_up_top_right() {
1146        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(9, 0);
1147
1148        assert_eq!(RectangleSpherePoint::new(9, 1), point.up());
1149    }
1150    
1151    #[test]
1152    fn test_rect_point_up_bottom_left() {
1153        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(0, 9);
1154
1155        assert_eq!(RectangleSpherePoint::new(0, 8), point.up());
1156    }
1157    
1158    #[test]
1159    fn test_rect_point_up_bottom_right() {
1160        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(9, 9);
1161
1162        assert_eq!(RectangleSpherePoint::new(4, 9), point.up());
1163    }
1164    
1165    #[test]
1166    fn test_rect_point_down_middle() {
1167        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(3, 4);
1168
1169        assert_eq!(RectangleSpherePoint::new(3, 5), point.down());
1170    }
1171    
1172    #[test]
1173    fn test_rect_point_down_top_left() {
1174        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(0, 0);
1175
1176        assert_eq!(RectangleSpherePoint::new(0, 1), point.down());
1177    }
1178    
1179    #[test]
1180    fn test_rect_point_down_top_right() {
1181        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(9, 0);
1182
1183        assert_eq!(RectangleSpherePoint::new(4, 0), point.down());
1184    }
1185    
1186    #[test]
1187    fn test_rect_point_down_bottom_left() {
1188        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(0, 9);
1189
1190        assert_eq!(RectangleSpherePoint::new(5, 9), point.down());
1191    }
1192    
1193    #[test]
1194    fn test_rect_point_down_bottom_right() {
1195        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(9, 9);
1196
1197        assert_eq!(RectangleSpherePoint::new(9, 8), point.down());
1198    }
1199
1200    #[test]
1201    fn test_rect_point_left_middle() {
1202        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(5, 5);
1203
1204        assert_eq!(RectangleSpherePoint::new(4, 5), point.left());
1205    }
1206    
1207    #[test]
1208    fn test_rect_point_left_left() {
1209        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(0, 5);
1210
1211        assert_eq!(RectangleSpherePoint::new(9, 5), point.left());
1212    }
1213   
1214    #[test]
1215    fn test_rect_point_left_right() {
1216        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(9, 5);
1217
1218        assert_eq!(RectangleSpherePoint::new(8, 5), point.left());
1219    }
1220
1221    #[test]
1222    fn test_rect_point_right_middle() {
1223        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(5, 5);
1224
1225        assert_eq!(RectangleSpherePoint::new(6, 5), point.right());
1226    }
1227    
1228    #[test]
1229    fn test_rect_point_right_left() {
1230        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(0, 5);
1231
1232        assert_eq!(RectangleSpherePoint::new(1, 5), point.right());
1233    }
1234   
1235    #[test]
1236    fn test_rect_point_right_right() {
1237        let point: RectangleSpherePoint<10, 10> = RectangleSpherePoint::new(9, 5);
1238
1239        assert_eq!(RectangleSpherePoint::new(0, 5), point.right());
1240    }
1241
1242    #[test]
1243    fn test_rect_point_from_geographic_equator() {
1244        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(0.0, PI);
1245
1246        assert_eq!(RectangleSpherePoint::new(50, 50), point);
1247    }
1248    
1249    #[test]
1250    fn test_rect_point_from_geographic_north_pole() {
1251        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(PI / 2.0, PI);
1252
1253        assert_eq!(RectangleSpherePoint::new(50, 0), point);
1254    }
1255    
1256    #[test]
1257    fn test_rect_point_from_geographic_south_pole() {
1258        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(-PI / 2.0, PI);
1259
1260        assert_eq!(RectangleSpherePoint::new(50, 99), point);
1261    }
1262    
1263    #[test]
1264    fn test_rect_point_from_geographic_equator_wrap_north() {
1265        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(-PI, PI);
1266
1267        assert_eq!(RectangleSpherePoint::new(50, 50), point);
1268    }
1269    
1270    #[test]
1271    fn test_rect_point_from_geographic_equator_wrap_south() {
1272        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(PI, PI);
1273
1274        assert_eq!(RectangleSpherePoint::new(50, 50), point);
1275    }
1276    
1277    #[test]
1278    fn test_rect_point_from_geographic_east() {
1279        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(0.0, PI * 2.0);
1280
1281        assert_eq!(RectangleSpherePoint::new(0, 50), point);
1282    }
1283    
1284    #[test]
1285    fn test_rect_point_from_geographic_west() {
1286        let point: RectangleSpherePoint<100, 100> = RectangleSpherePoint::from_geographic(0.0, 0.0);
1287
1288        assert_eq!(RectangleSpherePoint::new(0, 50), point);
1289    }
1290
1291    #[test]
1292    fn test_rect_point_up_loop() {
1293        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(0, 3);
1294
1295        assert_eq!(start, start.up().up().up().up().up().up().up().up().up().up());
1296    }
1297    
1298    #[test]
1299    fn test_rect_point_down_loop() {
1300        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(5, 3);
1301
1302        assert_eq!(start, start.down().down().down().down().down().down().down().down().down().down());
1303    }
1304    
1305    #[test]
1306    fn test_rect_point_left_loop() {
1307        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(0, 3);
1308
1309        assert_eq!(start, start.left().left().left().left().left().left().left().left().left().left());
1310    }
1311    
1312    #[test]
1313    fn test_rect_point_right_loop() {
1314        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(0, 3);
1315
1316        assert_eq!(start, start.right().right().right().right().right().right().right().right().right().right());
1317    }
1318
1319    #[test]
1320    fn test_rect_point_up_inverse_middle() {
1321        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(5, 3);
1322
1323        assert_eq!(start, start.up().down());
1324    }
1325    
1326    #[test]
1327    fn test_rect_point_down_inverse_middle() {
1328        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(5, 3);
1329
1330        assert_eq!(start, start.down().up());
1331    }
1332    
1333    #[test]
1334    fn test_rect_point_left_inverse_middle() {
1335        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(5, 3);
1336
1337        assert_eq!(start, start.left().right());
1338    }
1339    
1340    #[test]
1341    fn test_rect_point_right_inverse_middle() {
1342        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(5, 3);
1343
1344        assert_eq!(start, start.right().left());
1345    }
1346    
1347    #[test]
1348    fn test_rect_point_up_inverse_edge() {
1349        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(0, 0);
1350
1351        assert_eq!(start, start.up().down());
1352    }
1353    
1354    #[test]
1355    fn test_rect_point_down_inverse_edge() {
1356        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(0, 4);
1357
1358        assert_eq!(start, start.down().up());
1359    }
1360    
1361    #[test]
1362    fn test_rect_point_left_inverse_edge() {
1363        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(0, 0);
1364
1365        assert_eq!(start, start.left().right());
1366    }
1367    
1368    #[test]
1369    fn test_rect_point_right_inverse_edge() {
1370        let start: RectangleSpherePoint<10, 5> = RectangleSpherePoint::new(9, 0);
1371
1372        assert_eq!(start, start.right().left());
1373    }
1374
1375    #[test]
1376    fn test_rect_from_fn() {
1377        let grid: RectangleSphereGrid<u32, 200, 100> = RectangleSphereGrid::from_fn(|point| point.x + point.y);
1378
1379        assert_eq!(15, grid[RectangleSpherePoint::new(5, 10)]);
1380    }
1381
1382    #[test]
1383    fn test_rect_from_neighbours() {
1384        let grid: RectangleSphereGrid<u32, 20, 10> = RectangleSphereGrid::from_fn(|point| point.x);
1385
1386        let grid2 = grid.map_neighbours(|current, up, down, left, right| current + up + down + left + right);
1387
1388        assert_eq!(25, grid2[RectangleSpherePoint::new(5, 3)])
1389    }
1390    
1391    #[test]
1392    fn test_rect_from_neighbours_diagonals() {
1393        let grid: RectangleSphereGrid<u32, 20, 10> = RectangleSphereGrid::from_fn(|point| point.x);
1394
1395        let grid2 = grid.map_neighbours_diagonals(|up_left, up, up_right, left, current, right, down_left, down, down_right| up_left + up + up_right + left + current + right + down_left + down + down_right);
1396
1397        assert_eq!(4 * 3 + 5 * 3 + 6 * 3, grid2[RectangleSpherePoint::new(5, 3)])
1398    }
1399
1400    #[test]
1401    fn test_rect_point_latitude_0() {
1402        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 0.0);
1403
1404        assert_relative_eq!(0.0, point.latitude());
1405    }
1406    
1407    #[test]
1408    fn test_rect_point_latitude_1() {
1409        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.0, 0.0);
1410
1411        assert_relative_eq!(1.0, point.latitude(), epsilon = 0.001);
1412    }
1413    
1414    #[test]
1415    fn test_rect_point_latitude_minus_1() {
1416        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.0, 0.0);
1417
1418        assert_relative_eq!(-1.0, point.latitude(), epsilon = 0.001);
1419    }
1420    
1421    #[test]
1422    fn test_rect_point_latitude_0_far() {
1423        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 4.0);
1424
1425        assert_relative_eq!(0.0, point.latitude());
1426    }
1427    
1428    #[test]
1429    fn test_rect_point_latitude_1_far() {
1430        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.0, 2.0);
1431
1432        assert_relative_eq!(1.0, point.latitude(), epsilon = 0.001);
1433    }
1434    
1435    #[test]
1436    fn test_rect_point_latitude_minus_1_far() {
1437        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.0, 3.0);
1438
1439        assert_relative_eq!(-1.0, point.latitude(), epsilon = 0.001);
1440    }
1441    
1442    #[test]
1443    fn test_rect_point_longitude_0() {
1444        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 0.0);
1445
1446        assert_relative_eq!(0.0, point.longitude(), epsilon = 0.001);
1447    }
1448    
1449    #[test]
1450    fn test_rect_point_longitude_1() {
1451        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 1.0);
1452
1453        assert_relative_eq!(1.0, point.longitude(), epsilon = 0.001);
1454    }
1455    
1456    #[test]
1457    fn test_rect_point_longitude_2() {
1458        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 2.0);
1459
1460        assert_relative_eq!(2.0, point.longitude(), epsilon = 0.001);
1461    }
1462    
1463    #[test]
1464    fn test_rect_point_longitude_4() {
1465        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 4.0);
1466
1467        assert_relative_eq!(4.0, point.longitude(), epsilon = 0.001);
1468    }
1469    
1470    #[test]
1471    fn test_rect_point_longitude_6() {
1472        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(0.0, 6.0);
1473
1474        assert_relative_eq!(6.0, point.longitude(), epsilon = 0.001);
1475    }
1476    
1477    #[test]
1478    fn test_rect_point_longitude_0_north() {
1479        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.5, 0.0);
1480
1481        assert_relative_eq!(0.0, point.longitude(), epsilon = 0.001);
1482    }
1483    
1484    #[test]
1485    fn test_rect_point_longitude_1_north() {
1486        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.5, 1.0);
1487
1488        assert_relative_eq!(1.0, point.longitude(), epsilon = 0.001);
1489    }
1490    
1491    #[test]
1492    fn test_rect_point_longitude_2_north() {
1493        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.5, 2.0);
1494
1495        assert_relative_eq!(2.0, point.longitude(), epsilon = 0.001);
1496    }
1497    
1498    #[test]
1499    fn test_rect_point_longitude_4_north() {
1500        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.5, 4.0);
1501
1502        assert_relative_eq!(4.0, point.longitude(), epsilon = 0.001);
1503    }
1504    
1505    #[test]
1506    fn test_rect_point_longitude_6_north() {
1507        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(-1.5, 6.0);
1508
1509        assert_relative_eq!(6.0, point.longitude(), epsilon = 0.001);
1510    }
1511    
1512    #[test]
1513    fn test_rect_point_longitude_0_south() {
1514        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.5, 0.0);
1515
1516        assert_relative_eq!(0.0, point.longitude(), epsilon = 0.001);
1517    }
1518    
1519    #[test]
1520    fn test_rect_point_longitude_1_south() {
1521        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.5, 1.0);
1522
1523        assert_relative_eq!(1.0, point.longitude(), epsilon = 0.001);
1524    }
1525    
1526    #[test]
1527    fn test_rect_point_longitude_2_south() {
1528        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.5, 2.0);
1529
1530        assert_relative_eq!(2.0, point.longitude(), epsilon = 0.001);
1531    }
1532    
1533    #[test]
1534    fn test_rect_point_longitude_4_south() {
1535        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.5, 4.0);
1536
1537        assert_relative_eq!(4.0, point.longitude(), epsilon = 0.001);
1538    }
1539    
1540    #[test]
1541    fn test_rect_point_longitude_6_south() {
1542        let point: RectangleSpherePoint<1000000000, 500000000> = RectangleSpherePoint::from_geographic(1.5, 6.0);
1543
1544        assert_relative_eq!(6.0, point.longitude(), epsilon = 0.001);
1545    }
1546
1547    #[test]
1548    fn test_cube_point_up_middle() {
1549        let point: CubeSpherePoint<5> = CubeSpherePoint::new(CubeFace::Front, 3, 4);
1550
1551        assert_eq!(CubeSpherePoint::new(CubeFace::Front, 3, 3), point.up());
1552    }
1553    
1554    #[test]
1555    fn test_cube_point_up_top() {
1556        let point: CubeSpherePoint<5> = CubeSpherePoint::new(CubeFace::Front, 0, 0);
1557
1558        assert_eq!(CubeSpherePoint::new(CubeFace::Top, 0, 4), point.up());
1559    }
1560    
1561    #[test]
1562    fn test_cube_point_up_bottom() {
1563        let point: CubeSpherePoint<5> = CubeSpherePoint::new(CubeFace::Front, 0, 4);
1564
1565        assert_eq!(CubeSpherePoint::new(CubeFace::Front, 0, 3), point.up());
1566    }
1567    
1568    #[test]
1569    fn test_cube_point_down_middle() {
1570        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 3, 4);
1571
1572        assert_eq!(CubeSpherePoint::new(CubeFace::Front, 3, 5), point.down());
1573    }
1574    
1575    #[test]
1576    fn test_cube_point_down_top() {
1577        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 0, 0);
1578
1579        assert_eq!(CubeSpherePoint::new(CubeFace::Front, 0, 1), point.down());
1580    }
1581    
1582    #[test]
1583    fn test_cube_point_down_bottom() {
1584        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 0, 9);
1585
1586        assert_eq!(CubeSpherePoint::new(CubeFace::Bottom, 0, 0), point.down());
1587    }
1588
1589    #[test]
1590    fn test_cube_point_left_middle() {
1591        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Left, 5, 5);
1592
1593        assert_eq!(CubeSpherePoint::new(CubeFace::Left, 4, 5), point.left());
1594    }
1595    
1596    #[test]
1597    fn test_cube_point_left_left() {
1598        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Left, 0, 5);
1599
1600        assert_eq!(CubeSpherePoint::new(CubeFace::Back, 0, 5), point.left());
1601    }
1602   
1603    #[test]
1604    fn test_cube_point_left_right() {
1605        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Left, 9, 5);
1606
1607        assert_eq!(CubeSpherePoint::new(CubeFace::Left, 8, 5), point.left());
1608    }
1609
1610    #[test]
1611    fn test_cube_point_right_middle() {
1612        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Right, 5, 5);
1613
1614        assert_eq!(CubeSpherePoint::new(CubeFace::Right, 6, 5), point.right());
1615    }
1616    
1617    #[test]
1618    fn test_cube_point_right_left() {
1619        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Right, 0, 5);
1620
1621        assert_eq!(CubeSpherePoint::new(CubeFace::Right, 1, 5), point.right());
1622    }
1623   
1624    #[test]
1625    fn test_cube_point_right_right() {
1626        let point: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Right, 9, 5);
1627
1628        assert_eq!(CubeSpherePoint::new(CubeFace::Back, 9, 5), point.right());
1629    }
1630
1631    #[test]
1632    fn test_cube_point_from_geographic_equator() {
1633        let point: CubeSpherePoint<100> = CubeSpherePoint::from_geographic(0.0, PI);
1634
1635        assert_eq!(CubeSpherePoint::new(CubeFace::Back, 50, 50), point);
1636    }
1637    
1638    #[test]
1639    fn test_cube_point_from_geographic_north_pole() {
1640        let point: CubeSpherePoint<100> = CubeSpherePoint::from_geographic(PI / 2.0, PI);
1641
1642        assert_eq!(CubeSpherePoint::new(CubeFace::Top, 50, 50), point);
1643    }
1644    
1645    #[test]
1646    fn test_cube_point_from_geographic_south_pole() {
1647        let point: CubeSpherePoint<100> = CubeSpherePoint::from_geographic(-PI / 2.0, PI);
1648
1649        assert_eq!(CubeSpherePoint::new(CubeFace::Bottom, 50, 50), point);
1650    }
1651    
1652    #[test]
1653    fn test_cube_point_from_geographic_east() {
1654        let point: CubeSpherePoint<100> = CubeSpherePoint::from_geographic(0.0, -PI / 2.0);
1655
1656        assert_eq!(CubeSpherePoint::new(CubeFace::Left, 50, 50), point);
1657    }
1658    
1659    #[test]
1660    fn test_cube_point_from_geographic_west() {
1661        let point: CubeSpherePoint<100> = CubeSpherePoint::from_geographic(0.0, PI / 2.0);
1662
1663        assert_eq!(CubeSpherePoint::new(CubeFace::Right, 50, 50), point);
1664    }
1665    
1666    #[test]
1667    fn test_cube_point_from_geographic_less_west() {
1668        let point: CubeSpherePoint<100> = CubeSpherePoint::from_geographic(0.0, PI / 2.0 - 0.2);
1669
1670        assert_eq!(CubeSpherePoint::new(CubeFace::Right, 39, 50), point);
1671    }
1672
1673
1674    #[test]
1675    fn test_cube_point_up_loop() {
1676        let start: CubeSpherePoint<3> = CubeSpherePoint::new(CubeFace::Bottom, 1, 2);
1677
1678        assert_eq!(start, start.up().up().up()
1679                   .up().up().up()
1680                   .up().up().up()
1681                   .up().up().up());
1682    }
1683    
1684    #[test]
1685    fn test_cube_point_down_loop() {
1686        let start: CubeSpherePoint<3> = CubeSpherePoint::new(CubeFace::Top, 0, 0);
1687
1688        assert_eq!(start, start.down().down().down()
1689                   .down().down().down()
1690                   .down().down().down()
1691                   .down().down().down());
1692    }
1693    
1694    #[test]
1695    fn test_cube_point_left_loop() {
1696        let start: CubeSpherePoint<3> = CubeSpherePoint::new(CubeFace::Back, 1, 0);
1697
1698        assert_eq!(start, start.left().left().left()
1699                   .left().left().left()
1700                   .left().left().left()
1701                   .left().left().left());
1702    }
1703    
1704    #[test]
1705    fn test_cube_point_right_loop() {
1706        let start: CubeSpherePoint<3> = CubeSpherePoint::new(CubeFace::Front, 0, 2);
1707
1708        assert_eq!(start, start.right().right().right()
1709                   .right().right().right()
1710                   .right().right().right()
1711                   .right().right().right());
1712    }
1713
1714    #[test]
1715    fn test_cube_point_up_inverse_middle() {
1716        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 5, 3);
1717
1718        assert_eq!(start, start.up().down());
1719    }
1720    
1721    #[test]
1722    fn test_cube_point_down_inverse_middle() {
1723        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 5, 3);
1724
1725        assert_eq!(start, start.down().up());
1726    }
1727    
1728    #[test]
1729    fn test_cube_point_left_inverse_middle() {
1730        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 5, 3);
1731
1732        assert_eq!(start, start.left().right());
1733    }
1734    
1735    #[test]
1736    fn test_cube_point_right_inverse_middle() {
1737        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 5, 3);
1738
1739        assert_eq!(start, start.right().left());
1740    }
1741    
1742    #[test]
1743    fn test_cube_point_up_inverse_edge() {
1744        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 0, 0);
1745
1746        assert_eq!(start, start.up().down());
1747    }
1748    
1749    #[test]
1750    fn test_cube_point_down_inverse_edge() {
1751        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 0, 9);
1752
1753        assert_eq!(start, start.down().up());
1754    }
1755    
1756    #[test]
1757    fn test_cube_point_left_inverse_edge() {
1758        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 0, 0);
1759
1760        assert_eq!(start, start.left().right());
1761    }
1762    
1763    #[test]
1764    fn test_cube_point_right_inverse_edge() {
1765        let start: CubeSpherePoint<10> = CubeSpherePoint::new(CubeFace::Front, 9, 0);
1766
1767        assert_eq!(start, start.right().left());
1768    }
1769
1770    #[test]
1771    fn test_cube_from_fn() {
1772        let grid: CubeSphereGrid<u16, 100> = CubeSphereGrid::from_fn(|point| point.x + point.y);
1773
1774        assert_eq!(15, grid[CubeSpherePoint::new(CubeFace::Front, 5, 10)]);
1775    }
1776    
1777    #[test]
1778    fn test_cube_from_neighbours() {
1779        let grid: CubeSphereGrid<u16, 10> = CubeSphereGrid::from_fn(|point| point.x);
1780
1781        let grid2 = grid.map_neighbours(|current, up, down, left, right| current + up + down + left + right);
1782
1783        assert_eq!(25, grid2[CubeSpherePoint::new(CubeFace::Front, 5, 3)])
1784    }
1785    
1786    #[test]
1787    fn test_cube_from_neighbours_diagonals() {
1788        let grid: CubeSphereGrid<u16, 10> = CubeSphereGrid::from_fn(|point| point.x);
1789
1790        let grid2 = grid.map_neighbours_diagonals(|up_left, up, up_right, left, current, right, down_left, down, down_right| up_left + up + up_right + left + current + right + down_left + down + down_right);
1791
1792        assert_eq!(4 * 3 + 5 * 3 + 6 * 3, grid2[CubeSpherePoint::new(CubeFace::Front, 5, 3)])
1793    }
1794    
1795    #[test]
1796    fn test_cube_point_latitude_0() {
1797        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 0.0);
1798        
1799        println!("{:?}", point);
1800
1801        assert_relative_eq!(0.0, point.latitude(), epsilon = 0.01);
1802    }
1803    
1804    #[test]
1805    fn test_cube_point_latitude_1() {
1806        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.0, 0.0);
1807
1808        println!("{:?}", point);
1809        println!("{:?}", point.position(1.0));
1810
1811        assert_relative_eq!(1.0, point.latitude(), epsilon = 0.01);
1812    }
1813    
1814    #[test]
1815    fn test_cube_point_latitude_minus_1() {
1816        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.0, 0.0);
1817        
1818        println!("{:?}", point);
1819        println!("{:?}", point.position(1.0));
1820
1821        assert_relative_eq!(-1.0, point.latitude(), epsilon = 0.01);
1822    }
1823    
1824    #[test]
1825    fn test_cube_point_latitude_half() {
1826        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.5, 0.0);
1827
1828        println!("{:?}", point);
1829        println!("{:?}", point.position(1.0));
1830
1831        assert_relative_eq!(0.5, point.latitude(), epsilon = 0.01);
1832    }
1833    
1834    #[test]
1835    fn test_cube_point_latitude_minus_half() {
1836        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-0.5, 0.0);
1837        
1838        println!("{:?}", point);
1839        println!("{:?}", point.position(1.0));
1840
1841        assert_relative_eq!(-0.5, point.latitude(), epsilon = 0.01);
1842    }
1843    
1844    #[test]
1845    fn test_cube_point_latitude_0_far() {
1846        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 3.0);
1847        
1848        println!("{:?}", point);
1849        println!("{:?}", point.position(1.0));
1850
1851        assert_relative_eq!(0.0, point.latitude(), epsilon = 0.01);
1852    }
1853    
1854    #[test]
1855    fn test_cube_point_latitude_1_far() {
1856        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.0, 2.0);
1857        
1858        println!("{:?}", point);
1859        println!("{:?}", point.position(1.0));
1860
1861        assert_relative_eq!(1.0, point.latitude(), epsilon = 0.1);
1862    }
1863    
1864    #[test]
1865    fn test_cube_point_latitude_minus_1_far() {
1866        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.0, 3.0);
1867        
1868        println!("{:?}", point);
1869        println!("{:?}", point.position(1.0));
1870
1871        assert_relative_eq!(-1.0, point.latitude(), epsilon = 0.01);
1872    }
1873    
1874    #[test]
1875    fn test_cube_point_latitude_half_far() {
1876        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.5, 5.0);
1877
1878        println!("{:?}", point);
1879        println!("{:?}", point.position(1.0));
1880
1881        assert_relative_eq!(0.5, point.latitude(), epsilon = 0.01);
1882    }
1883    
1884    #[test]
1885    fn test_cube_point_latitude_minus_half_far() {
1886        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-0.5, 3.0);
1887        
1888        println!("{:?}", point);
1889        println!("{:?}", point.position(1.0));
1890
1891        assert_relative_eq!(-0.5, point.latitude(), epsilon = 0.01);
1892    }
1893   
1894    #[test]
1895    fn test_cube_point_longitude_0() {
1896        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 0.0);
1897        
1898        println!("{:?}", point);
1899        println!("{:?}", point.position(1.0));
1900
1901        assert_relative_eq!(0.0, point.longitude(), epsilon = 0.01);
1902    }
1903    
1904    #[test]
1905    fn test_cube_point_longitude_1() {
1906        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 1.0);
1907        
1908        println!("{:?}", point);
1909        println!("{:?}", point.position(1.0));
1910
1911        assert_relative_eq!(1.0, point.longitude(), epsilon = 0.01);
1912    }
1913    
1914    #[test]
1915    fn test_cube_point_longitude_2() {
1916        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 2.0);
1917        
1918        println!("{:?}", point);
1919        println!("{:?}", point.position(1.0));
1920
1921        assert_relative_eq!(2.0, point.longitude(), epsilon = 0.01);
1922    }
1923    
1924    #[test]
1925    fn test_cube_point_longitude_3() {
1926        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 3.0);
1927        
1928        println!("{:?}", point);
1929        println!("{:?}", point.position(1.0));
1930
1931        assert_relative_eq!(3.0, point.longitude(), epsilon = 0.01);
1932    }
1933    
1934    #[test]
1935    fn test_cube_point_longitude_4() {
1936        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 4.0);
1937        
1938        println!("{:?}", point);
1939        println!("{:?}", point.position(1.0));
1940
1941        assert_relative_eq!(4.0, point.longitude(), epsilon = 0.01);
1942    }
1943    
1944    #[test]
1945    fn test_cube_point_longitude_5() {
1946        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 5.0);
1947        
1948        println!("{:?}", point);
1949        println!("{:?}", point.position(1.0));
1950
1951        assert_relative_eq!(5.0, point.longitude(), epsilon = 0.01);
1952    }
1953    
1954    #[test]
1955    fn test_cube_point_longitude_6() {
1956        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(0.0, 6.0);
1957        
1958        println!("{:?}", point);
1959        println!("{:?}", point.position(1.0));
1960
1961        assert_relative_eq!(6.0, point.longitude(), epsilon = 0.01);
1962    }
1963    
1964    #[test]
1965    fn test_cube_point_longitude_0_north() {
1966        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.5, 0.0);
1967        
1968        println!("{:?}", point);
1969        println!("{:?}", point.position(1.0));
1970
1971        assert_relative_eq!(0.0, point.longitude(), epsilon = 0.01);
1972    }
1973    
1974    #[test]
1975    fn test_cube_point_longitude_1_north() {
1976        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.5, 1.0);
1977        
1978        println!("{:?}", point);
1979        println!("{:?}", point.position(1.0));
1980
1981        assert_relative_eq!(1.0, point.longitude(), epsilon = 0.01);
1982    }
1983    
1984    #[test]
1985    fn test_cube_point_longitude_2_north() {
1986        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.5, 2.0);
1987        
1988        println!("{:?}", point);
1989        println!("{:?}", point.position(1.0));
1990
1991        assert_relative_eq!(2.0, point.longitude(), epsilon = 0.01);
1992    }
1993    
1994    #[test]
1995    fn test_cube_point_longitude_4_north() {
1996        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.5, 4.0);
1997        
1998        println!("{:?}", point);
1999        println!("{:?}", point.position(1.0));
2000
2001        assert_relative_eq!(4.0, point.longitude(), epsilon = 0.001);
2002    }
2003    
2004    #[test]
2005    fn test_cube_point_longitude_6_north() {
2006        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(-1.5, 6.0);
2007        
2008        println!("{:?}", point);
2009        println!("{:?}", point.position(1.0));
2010
2011        assert_relative_eq!(6.0, point.longitude(), epsilon = 0.01);
2012    }
2013    
2014    #[test]
2015    fn test_cube_point_longitude_0_south() {
2016        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.5, 0.0);
2017        
2018        println!("{:?}", point);
2019        println!("{:?}", point.position(1.0));
2020
2021        assert_relative_eq!(0.0, point.longitude(), epsilon = 0.01);
2022    }
2023    
2024    #[test]
2025    fn test_cube_point_longitude_1_south() {
2026        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.5, 1.0);
2027        
2028        println!("{:?}", point);
2029        println!("{:?}", point.position(1.0));
2030
2031        assert_relative_eq!(1.0, point.longitude(), epsilon = 0.01);
2032    }
2033    
2034    #[test]
2035    fn test_cube_point_longitude_2_south() {
2036        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.5, 2.0);
2037        
2038        println!("{:?}", point);
2039        println!("{:?}", point.position(1.0));
2040
2041        assert_relative_eq!(2.0, point.longitude(), epsilon = 0.01);
2042    }
2043    
2044    #[test]
2045    fn test_cube_point_longitude_4_south() {
2046        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.5, 4.0);
2047        
2048        println!("{:?}", point);
2049        println!("{:?}", point.position(1.0));
2050
2051        assert_relative_eq!(4.0, point.longitude(), epsilon = 0.01);
2052    }
2053    
2054    #[test]
2055    fn test_cube_point_longitude_6_south() {
2056        let point: CubeSpherePoint<32000> = CubeSpherePoint::from_geographic(1.5, 6.0);
2057        
2058        println!("{:?}", point);
2059        println!("{:?}", point.position(1.0));
2060
2061        assert_relative_eq!(6.0, point.longitude(), epsilon = 0.01);
2062    }
2063
2064    #[test]
2065    fn test_cube_clone_128() {
2066        let grid: CubeSphereGrid<u64, 128> = CubeSphereGrid::default();
2067
2068        assert_eq!(grid, black_box(grid.clone()));
2069    }
2070    
2071    #[test]
2072    fn test_cube_clone_128_large_struct() {
2073        let grid: CubeSphereGrid<[u8; 1024], 128> = CubeSphereGrid::from_fn(|_| [0b11101101; 1024]);
2074
2075        assert_eq!(grid, black_box(grid.clone()));
2076    }
2077    
2078    #[test]
2079    fn test_cube_clone_4096() {
2080        let grid: CubeSphereGrid<u64, 4096> = CubeSphereGrid::default();
2081
2082        assert_eq!(grid, black_box(grid.clone()));
2083    }
2084}
2085