1use crate::consts::*;
19use crate::r1;
20use crate::r2;
21use crate::s1;
22use crate::s1::*;
23use crate::s2;
24use crate::s2::cap::Cap;
25use crate::s2::cellid::*;
26use crate::s2::latlng::*;
27use crate::s2::metric::*;
28use crate::s2::point::*;
29use crate::s2::region::Region;
30use crate::s2::stuv::*;
31use std::f64::consts::PI;
32
33lazy_static! {
34 static ref POLE_MIN_LAT: f64 = (1. / 3f64).sqrt().asin() - 0.5 * DBL_EPSILON;
35}
36
37#[derive(Debug, Clone)]
41#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
42pub struct Cell {
43 face: u8,
44 level: u8,
45 pub orientation: u8,
46 pub id: CellID,
47 pub uv: r2::rect::Rect,
48}
49
50impl<'a> From<&'a CellID> for Cell {
51 fn from(id: &'a CellID) -> Self {
52 let (f, i, j, o) = id.face_ij_orientation();
53 assert!(f < 6);
54 let level = id.level();
55 Cell {
56 face: f as u8,
57 level: level as u8,
58 orientation: o as u8,
59 id: *id,
60 uv: ij_level_to_bound_uv(i, j, level),
61 }
62 }
63}
64impl From<CellID> for Cell {
65 fn from(id: CellID) -> Self {
66 Self::from(&id)
67 }
68}
69
70impl<'a> From<&'a Point> for Cell {
71 fn from(p: &'a Point) -> Self {
72 Cell::from(CellID::from(p))
73 }
74}
75impl From<Point> for Cell {
76 fn from(p: Point) -> Self {
77 Self::from(&p)
78 }
79}
80
81impl<'a> From<&'a LatLng> for Cell {
82 fn from(ll: &'a LatLng) -> Self {
83 Self::from(CellID::from(ll))
84 }
85}
86impl From<LatLng> for Cell {
87 fn from(ll: LatLng) -> Self {
88 Self::from(&ll)
89 }
90}
91
92impl<'a> From<&'a Cell> for CellID {
93 fn from(c: &'a Cell) -> Self {
94 c.id
95 }
96}
97impl From<Cell> for CellID {
98 fn from(c: Cell) -> Self {
99 Self::from(&c)
100 }
101}
102
103impl Cell {
104 pub fn face(&self) -> u8 {
105 self.face
106 }
107
108 pub fn level(&self) -> u8 {
109 self.level
110 }
111
112 pub fn is_leaf(&self) -> bool {
113 self.level == MAX_LEVEL as u8
114 }
115
116 pub fn size_ij(&self) -> u64 {
117 size_ij(u64::from(self.level))
118 }
119
120 pub fn vertex(&self, k: usize) -> Point {
123 let v = &self.uv.vertices()[k];
124 Point(face_uv_to_xyz(self.face, v.x, v.y).normalize())
125 }
126
127 pub fn vertices(&self) -> [Point; 4] {
128 let verts = self.uv.vertices();
129 [
130 Point(face_uv_to_xyz(self.face, verts[0].x, verts[0].y).normalize()),
131 Point(face_uv_to_xyz(self.face, verts[1].x, verts[1].y).normalize()),
132 Point(face_uv_to_xyz(self.face, verts[2].x, verts[2].y).normalize()),
133 Point(face_uv_to_xyz(self.face, verts[3].x, verts[3].y).normalize()),
134 ]
135 }
136
137 pub fn edge(&self, k: usize) -> Point {
140 match k {
141 0 => Point(vnorm(self.face, self.uv.y.lo).normalize()),
142 1 => Point(unorm(self.face, self.uv.x.hi).normalize()),
143 2 => Point((vnorm(self.face, self.uv.y.hi) * -1.).normalize()),
144 3 => Point((unorm(self.face, self.uv.x.lo) * -1.).normalize()),
145 _ => unimplemented!(),
146 }
147 }
148
149 pub fn bound_uv(&self) -> &r2::rect::Rect {
151 &self.uv
152 }
153
154 pub fn center(&self) -> Point {
159 Point(self.id.raw_point().normalize())
160 }
161
162 pub fn children(&self) -> Option<[Cell; 4]> {
167 if self.is_leaf() {
169 return None;
170 }
171 let mut children = [self.clone(), self.clone(), self.clone(), self.clone()];
173
174 let uv_mid = self.id.center_uv();
175
176 let mut cid = self.id.child_begin();
177 for pos in 0..4 {
178 children[pos] = Cell {
179 face: self.face,
180 level: self.level + 1,
181 orientation: self.orientation ^ (POS_TO_ORIENTATION[pos]),
182 id: cid,
183 uv: self.uv.clone(),
184 };
185
186 let ij = POS_TO_IJ[self.orientation as usize][pos];
190 let i = ij >> 1;
191 let j = ij & 1;
192 if i == 1 {
193 children[pos].uv.x.hi = self.uv.x.hi;
194 children[pos].uv.x.lo = uv_mid.x;
195 } else {
196 children[pos].uv.x.lo = self.uv.x.lo;
197 children[pos].uv.x.hi = uv_mid.x;
198 }
199 if j == 1 {
200 children[pos].uv.y.hi = self.uv.y.hi;
201 children[pos].uv.y.lo = uv_mid.y;
202 } else {
203 children[pos].uv.y.lo = self.uv.y.lo;
204 children[pos].uv.y.hi = uv_mid.y;
205 }
206 cid = cid.next();
207 }
208
209 Some(children)
210 }
211
212 pub fn exact_area(&self) -> f64 {
214 let verts = self.vertices();
215 point_area(&verts[0], &verts[1], &verts[2]) + point_area(&verts[0], &verts[2], &verts[3])
216 }
217
218 pub fn approx_area(&self) -> f64 {
223 if self.level < 2 {
225 return self.average_area();
226 }
227
228 let verts = self.vertices();
232 let flat_area = 0.5
233 * (&verts[2] - &verts[0])
234 .0
235 .cross(&(&verts[3] - &verts[1]).0)
236 .norm();
237
238 flat_area * 2. / (1. + (1. - (1. / PI * flat_area).min(1.)).sqrt())
245 }
246
247 pub fn average_area(&self) -> f64 {
250 AVG_AREAMETRIC.value(self.level)
251 }
252
253 fn uv_from_ij(&self, i: i32, j: i32) -> (f64, f64) {
254 match (i, j) {
255 (0, 0) => (self.uv.x.lo, self.uv.y.lo),
256 (0, 1) => (self.uv.x.lo, self.uv.y.hi),
257 (1, 0) => (self.uv.x.hi, self.uv.y.lo),
258 (1, 1) => (self.uv.x.hi, self.uv.y.hi),
259 _ => panic!("i and/or j is out of bound"),
260 }
261 }
262
263 fn point_from_ij(&self, i: i32, j: i32) -> Point {
264 let (u, v) = self.uv_from_ij(i, j);
265 Point(face_uv_to_xyz(self.face, u, v))
266 }
267
268 pub fn latitude(&self, i: i32, j: i32) -> Angle {
270 self.point_from_ij(i, j).latitude()
271 }
272
273 pub fn longitude(&self, i: i32, j: i32) -> Angle {
275 self.point_from_ij(i, j).longitude()
276 }
277
278 pub fn rect_bound(&self) -> s2::rect::Rect {
280 if self.level > 0 {
281 let u = self.uv.x.lo + self.uv.x.hi;
293 let v = self.uv.y.lo + self.uv.y.hi;
294 let i = if u_axis(self.face).0.z == 0. {
295 if u < 0. {
296 1
297 } else {
298 0
299 }
300 } else {
301 if u > 0. {
302 1
303 } else {
304 0
305 }
306 };
307 let j = if v_axis(self.face).0.z == 0. {
308 if v < 0. {
309 1
310 } else {
311 0
312 }
313 } else {
314 if v > 0. {
315 1
316 } else {
317 0
318 }
319 };
320
321 let lat = r1::interval::Interval::from_point(self.latitude(i, j).rad())
322 + self.latitude(1 - i, 1 - j).rad();
323 let lng = s1::interval::EMPTY
324 + self.longitude(i, 1 - j).rad()
325 + self.longitude(1 - i, j).rad();
326
327 let max_err = Angle::from(Rad(2. * DBL_EPSILON));
344 return s2::rect::Rect { lat, lng }
345 .expanded(&LatLng {
346 lat: max_err,
347 lng: max_err,
348 })
349 .polar_closure();
350 }
351
352 const PI_4: f64 = PI / 4.;
357 let bound = match self.face {
358 0 => s2::rect::Rect {
359 lat: r1::interval::Interval::new(-PI_4, PI_4),
360 lng: s1::Interval::new(-PI_4, PI_4),
361 },
362 1 => s2::rect::Rect {
363 lat: r1::interval::Interval::new(-PI_4, PI_4),
364 lng: s1::Interval::new(PI_4, 3. * PI_4),
365 },
366 2 => s2::rect::Rect {
367 lat: r1::interval::Interval::new(*POLE_MIN_LAT, PI / 2.),
368 lng: s1::interval::FULL,
369 },
370 3 => s2::rect::Rect {
371 lat: r1::interval::Interval::new(-PI_4, PI_4),
372 lng: s1::Interval::new(3. * PI_4, -3. * PI_4),
373 },
374 4 => s2::rect::Rect {
375 lat: r1::interval::Interval::new(-PI_4, PI_4),
376 lng: s1::Interval::new(-3. * PI_4, -PI_4),
377 },
378 5 => s2::rect::Rect {
379 lat: r1::interval::Interval::new(-PI / 2., -1. * (*POLE_MIN_LAT)),
380 lng: s1::interval::FULL,
381 },
382 _ => panic!("invalid face"),
383 };
384
385 bound.expanded(&LatLng {
392 lat: Rad(DBL_EPSILON).into(),
393 lng: Rad(0.).into(),
394 })
395 }
396
397 pub fn contains_point(&self, p: &Point) -> bool {
405 if let Some((u, v)) = face_xyz_to_uv(self.face, p) {
406 let uv = r2::point::Point { x: u, y: v };
407
408 self.uv.expanded_by_margin(DBL_EPSILON).contains_point(&uv)
416 } else {
417 false
418 }
419 }
420}
421
422impl Region for Cell {
423 fn cap_bound(&self) -> Cap {
425 let center = self.uv.center();
429 let v: Point = Point(face_uv_to_xyz(self.face, center.x, center.y).normalize());
430 let mut cap = Cap::from(&v);
431
432 let vertices = self.vertices();
433 for vert in &vertices {
434 cap = cap + vert;
435 }
436 cap
437 }
438
439 fn intersects_cell(&self, other: &Cell) -> bool {
441 self.id.intersects(&other.id)
442 }
443
444 fn contains_cell(&self, other: &Cell) -> bool {
446 self.id.contains(&other.id)
447 }
448}
449
450#[cfg(test)]
457mod tests {
458 extern crate rand;
459
460 use super::*;
461 use rand::Rng;
462 use std;
463 use std::collections::BTreeMap;
464
465 use crate::s2::random;
466
467 const MAX_CELL_SIZE: usize = 48;
469
470 #[test]
471 fn test_cell_object_size() {
472 assert!(std::mem::size_of::<Cell>() <= MAX_CELL_SIZE);
473 }
474
475 fn format_f64(f: f64) -> String {
483 if f == 0.0 || f == -0.0 {
484 String::from("±0.0")
485 } else {
486 format!("{:0.20}", f)
487 }
488 }
489
490 fn incr(m: &mut BTreeMap<String, usize>, p: Point) {
491 let key = format!(
492 "{},{},{}",
493 format_f64(p.0.x),
494 format_f64(p.0.y),
495 format_f64(p.0.z)
496 );
497 *m.entry(key).or_insert(0) += 1;
498 }
499
500 #[test]
501 fn test_cell_faces() {
502 let mut edge_counts = BTreeMap::new();
503 let mut vert_counts = BTreeMap::new();
504 for face in 0..6 {
505 let id = CellID::from_face(face);
506 let cell = Cell::from(&id);
507
508 assert_eq!(cell.id, id);
509 assert_eq!(cell.face as u64, face);
510 assert_eq!(cell.level, 0);
511
512 assert_eq!(cell.orientation, cell.face & SWAP_MASK);
515
516 assert_eq!(cell.is_leaf(), false);
517 let verts = cell.vertices();
518 for k in 0..4 {
519 let edge = cell.edge(k);
520 let vert = verts[k];
521 incr(&mut edge_counts, edge);
522 incr(&mut vert_counts, vert);
523
524 let vert_cross = verts[(k + 1) & 3];
525 assert_f64_eq!(0., vert.0.dot(&edge.0));
526 assert_f64_eq!(0., vert_cross.0.dot(&edge.0));
527 assert_f64_eq!(1., vert.0.cross(&vert_cross.0).normalize().dot(&edge.0));
528 }
529 }
530
531 for (k, v) in &edge_counts {
534 assert_eq!(*v, 2, "edge {} counts wrong, got {}, want 2", k, v);
535 }
536
537 for (k, v) in &vert_counts {
538 assert_eq!(*v, 3, "vertex {} counts wrong, got {}, want 3", k, v);
539 }
540 }
541
542 fn test_cell_children_case(cell: &Cell) {
543 if cell.is_leaf() {
544 assert!(cell.children().is_none());
545 return;
546 }
547
548 let children = cell.children().expect("no children for non-leaf cell");
549 let mut child_id = cell.id.child_begin();
550 for (i, child) in children.iter().enumerate() {
551 assert_eq!(child_id, child.id);
552
553 let direct = Cell::from(&child.id);
554 assert_eq!(direct.face, child.face);
555 assert_eq!(direct.level, child.level);
556 assert_eq!(direct.orientation, child.orientation);
557 assert_eq!(true, direct.center().approx_eq(&child.center()));
558
559 let direct_verts = direct.vertices();
560 let child_verts = child.vertices();
561
562 for k in 0..4 {
563 assert!(direct_verts[k].0.approx_eq(&child_verts[k].0));
564 assert_eq!(direct.edge(k), child.edge(k));
565 }
566
567 assert_eq!(true, cell.contains_cell(&child));
568 assert_eq!(true, cell.intersects_cell(&child));
569 assert_eq!(false, child.contains_cell(&cell));
570 assert_eq!(true, child.intersects_cell(&cell));
571
572 for j in 0..4 {
573 assert_eq!(true, cell.contains_point(&child_verts[j]));
574 if j != i {
575 assert_eq!(false, child.contains_point(&children[j].center()));
576 assert_eq!(false, child.intersects_cell(&children[j]));
577 }
578 }
579
580 let parent_cap = cell.cap_bound();
581 let parent_rect = cell.rect_bound();
582
583 if cell.contains_point(&Point::from_coords(0., 0., 1.))
584 || cell.contains_point(&Point::from_coords(0., 0., -1.))
585 {
586 assert_eq!(true, parent_rect.lng.is_full());
587 }
588
589 let child_cap = child.cap_bound();
590 let child_rect = child.rect_bound();
591 let child_center = child.center();
592
593 assert_eq!(true, child_cap.contains_point(&child_center));
594 assert_eq!(
595 true,
596 child_rect.contains_point(&child_center),
597 "child_rect {:?}.contains_point({:?}.center()) = false, want true",
598 child_rect,
599 child
600 );
601 assert_eq!(true, parent_cap.contains_point(&child_center));
602 assert_eq!(true, parent_rect.contains_point(&child_center));
603
604 for j in 0..4 {
605 let v = &child_verts[j];
606 assert_eq!(true, child_cap.contains_point(&v));
607 assert_eq!(true, child_rect.contains_point(&v));
608 assert_eq!(true, parent_cap.contains_point(&v));
609 assert_eq!(true, parent_rect.contains_point(&v));
610
611 if j != i {
612 let mut cap_count = 0;
615 let mut rect_count = 0;
616 let verts = children[j].vertices();
617
618 for k in 0..4 {
619 if child_cap.contains_point(&verts[k]) {
620 cap_count += 1;
621 }
622 if child_rect.contains_point(&verts[k]) {
623 rect_count += 1;
624 }
625 }
626 assert!(cap_count < 3);
627 if child_rect.lat.lo > PI / 2. && child_rect.lat.hi < PI / 2. {
628 assert!(rect_count < 3);
629 }
630 }
631 }
632
633 let max_size_uv = 0.3964182625366691;
639 let special_uv = [
640 r2::point::Point::new(DBL_EPSILON, DBL_EPSILON), r2::point::Point::new(DBL_EPSILON, 1.), r2::point::Point::new(1., 1.), r2::point::Point::new(max_size_uv, max_size_uv), r2::point::Point::new(DBL_EPSILON, max_size_uv), ];
646
647 let mut force_subdivide = false;
648 for uv in special_uv.iter() {
649 if child.bound_uv().contains_point(uv) {
650 force_subdivide = true;
651 }
652 }
653
654 if force_subdivide || cell.level < 5 {
657 test_cell_children_case(child);
658 }
659
660 child_id = child_id.next();
661 }
662 }
663
664 #[test]
665 fn test_cell_children() {
666 test_cell_children_case(&Cell::from(CellID::from_face(0)));
667 test_cell_children_case(&Cell::from(CellID::from_face(3)));
668 test_cell_children_case(&Cell::from(CellID::from_face(5)));
669 }
670
671 #[test]
672 fn test_cell_areas() {
673 let exact_error = (1. + 1e-6f64).ln();
675 let approx_error = (1.03f64).ln();
676 let avg_error = (1. + 1e-15f64).ln();
677
678 let level1_cell = CellID(0x1000000000000000);
680 let want_area = 4. * PI / 6.;
681
682 assert_f64_eq!(Cell::from(&level1_cell).exact_area(), want_area);
683
684 let mut child_index = 1;
687 let mut ci = CellID(0x1000000000000000);
688 while ci.level() < 21 {
689 let mut exact_area = 0.;
690 let mut approx_area = 0.;
691 let mut avg_area = 0.;
692
693 for child in ci.children().iter() {
694 exact_area += Cell::from(child).exact_area();
695 approx_area += Cell::from(child).approx_area();
696 avg_area += Cell::from(child).average_area();
697 }
698
699 let cell = Cell::from(&ci);
700
701 assert_f64_eq!(exact_area, cell.exact_area());
702
703 child_index = (child_index + 1) % 4;
704
705 assert!((exact_area / cell.exact_area()).ln().abs() < exact_error);
709
710 assert!((approx_area / cell.approx_area()).ln().abs() < approx_error);
712
713 assert!((avg_area / cell.average_area()).ln().abs() < avg_error);
716
717 ci = ci.children()[child_index].clone();
718 }
719 }
720
721 fn test_cell_intersects_cell_case(a: CellID, b: CellID, want: bool) {
722 assert_eq!(want, Cell::from(a).intersects_cell(&Cell::from(b)));
723 }
724
725 #[test]
726 fn test_cell_intersects_cell() {
727 test_cell_intersects_cell_case(
728 CellID::from_face(0).child_begin_at_level(2),
729 CellID::from_face(0).child_begin_at_level(2),
730 true,
731 );
732
733 test_cell_intersects_cell_case(
734 CellID::from_face(0).child_begin_at_level(2),
735 CellID::from_face(0)
736 .child_begin_at_level(2)
737 .child_begin_at_level(5),
738 true,
739 );
740
741 test_cell_intersects_cell_case(
742 CellID::from_face(0).child_begin_at_level(2),
743 CellID::from_face(0).child_begin_at_level(2).next(),
744 false,
745 );
746
747 test_cell_intersects_cell_case(
748 CellID::from_face(0).child_begin_at_level(2).next(),
749 CellID::from_face(0).child_begin_at_level(2),
750 false,
751 );
752 }
753
754 fn test_cell_rect_bound_case(lat: f64, lng: f64) {
755 let c = Cell::from(LatLng::new(Deg(lat).into(), Deg(lng).into()));
756 let rect = c.rect_bound();
757 let verts = c.vertices();
758 for i in 0..4 {
759 assert!(rect.contains_latlng(&LatLng::from(&verts[i])));
760 }
761 }
762
763 #[test]
764 fn test_cell_rect_bound() {
765 test_cell_rect_bound_case(50., 50.);
766 test_cell_rect_bound_case(-50., 50.);
767 test_cell_rect_bound_case(50., -50.);
768 test_cell_rect_bound_case(-50., -50.);
769 test_cell_rect_bound_case(0., 0.);
770 test_cell_rect_bound_case(0., 180.);
771 test_cell_rect_bound_case(0., -179.);
772 }
773
774 #[test]
775 fn test_cell_cap_bound() {
776 let c = Cell::from(CellID::from_face(0).child_begin_at_level(20));
777 let s2_cap = c.cap_bound();
778
779 let verts = c.vertices();
780 for i in 0..4 {
781 assert!(s2_cap.contains_point(&verts[i]));
782 }
783 }
784
785 fn test_cell_contains_point_case(a: &Cell, b: &Point, want: bool) {
786 assert_eq!(want, a.contains_point(b));
787 }
788
789 #[test]
790 fn test_cell_contains_point() {
791 let id = CellID::from_face(0);
792
793 test_cell_contains_point_case(
794 &Cell::from(id.child_begin_at_level(2)),
795 &Cell::from(id.child_begin_at_level(2).child_begin_at_level(5)).vertices()[1],
796 true,
797 );
798
799 test_cell_contains_point_case(
800 &Cell::from(id.child_begin_at_level(2)),
801 &Cell::from(id.child_begin_at_level(2)).vertices()[1],
802 true,
803 );
804
805 test_cell_contains_point_case(
806 &Cell::from(id.child_begin_at_level(2).child_begin_at_level(5)),
807 &Cell::from(id.child_begin_at_level(2).next().child_begin_at_level(5)).vertices()[1],
808 false,
809 );
810 }
811
812 use crate::s2::edgeutil;
813
814 #[test]
815 fn test_cell_contains_point_consistent_will_s2_cellid_from_point() {
816 let mut rng = random::rng();
819
820 for _ in 0..1000 {
821 let cell = Cell::from(&random::cellid(&mut rng));
822 let i1 = rng.gen_range(0..4);
823 let i2 = (i1 + 1) & 3;
824 let v1 = &cell.vertices()[i1];
825
826 let v2 = random::sample_point_from_cap(
827 &mut rng,
828 Cap::from_center_angle(&cell.vertex(i2), &Angle::from(Rad(EPSILON))),
829 );
830 let p = edgeutil::interpolate(rng.gen_range(0.0..1.0), &v1, &v2);
831
832 assert!(Cell::from(&CellID::from(&p)).contains_point(&p));
833 }
834 }
835
836 #[test]
837 fn test_cell_contains_point_contains_ambiguous_point() {
838 let p = Point::from(LatLng::new(Deg(-2.).into(), Deg(90.).into()));
851 let cell = Cell::from(CellID::from(&p).parent(1));
852 assert_eq!(true, cell.contains_point(&p));
853 }
854}