1use 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
11pub trait SpherePoint : GridPoint {
13 fn from_geographic(latitude: f64, longitude: f64) -> Self;
18
19 fn latitude(&self) -> f64;
21
22 fn longitude(&self) -> f64;
24
25 fn sphere_coordinates(&self) -> (f64, f64) {
29 (self.longitude(), self.latitude())
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
42pub struct RectangleSphereGrid<T, const W: usize, const H: usize> {
43 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
175pub struct RectangleSpherePoint<const W: usize, const H: usize> {
176 x: u32,
178 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#[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#[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 fn new(face: CubeFace, x: u16, y: u16) -> Self {
605 Self {
606 face,
607 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1110#[repr(u32)] enum 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