1use super::{CoordIJK, Vec2d, SQRT3_2};
13use crate::{
14 face::{self, FaceOrientIJK},
15 index::bits,
16 BaseCell, Boundary, CellIndex, Direction, ExtendedResolution, Face, LatLng,
17 Resolution, Vertex, CCW, CW, DEFAULT_CELL_INDEX, NUM_HEX_VERTS,
18 NUM_ICOSA_FACES, NUM_PENT_VERTS,
19};
20
21static ZERO: CoordIJK = CoordIJK::new(0, 0, 0);
22
23#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
27pub struct FaceIJK {
28 pub face: Face,
30 pub coord: CoordIJK,
32}
33
34impl FaceIJK {
35 pub const fn new(face: Face, coord: CoordIJK) -> Self {
36 Self { face, coord }
37 }
38
39 #[allow(
42 clippy::cast_sign_loss,
43 reason = "safe because components values are in [0; 2]"
44 )]
45 pub fn base_cell_rotation(&self) -> Rotation {
46 debug_assert!(
48 (0..=2).contains(&self.coord.i())
49 && (0..=2).contains(&self.coord.j())
50 && (0..=2).contains(&self.coord.k())
51 );
52
53 let f = usize::from(self.face);
54 let i = self.coord.i() as usize;
55 let j = self.coord.j() as usize;
56 let k = self.coord.k() as usize;
57
58 FACE_IJK_BASE_CELLS[f][i][j][k]
59 }
60
61 pub(crate) fn to_cell(mut self, resolution: Resolution) -> CellIndex {
63 let mut bits = bits::set_resolution(DEFAULT_CELL_INDEX, resolution);
65
66 if resolution == Resolution::Zero {
68 let rotation = self.base_cell_rotation();
69 return CellIndex::new_unchecked(h3o_bit::set_base_cell(
70 bits,
71 rotation.base_cell.into(),
72 ));
73 }
74
75 self.coord =
79 directions_bits_from_ijk(self.coord, &mut bits, resolution);
80
81 let rotation = self.base_cell_rotation();
83 bits = h3o_bit::set_base_cell(bits, rotation.base_cell.into());
84
85 if rotation.base_cell.is_pentagon() {
88 if bits::first_axe(bits) == Direction::K.axe() {
90 if rotation.base_cell.is_cw_offset(self.face) {
92 bits = bits::rotate60::<{ CW }>(bits, 1);
93 } else {
94 bits = bits::rotate60::<{ CCW }>(bits, 1);
95 }
96 }
97
98 for _ in 0..rotation.count {
99 bits = bits::pentagon_rotate60::<{ CCW }>(bits);
100 }
101 } else {
102 bits = bits::rotate60::<{ CCW }>(bits, rotation.count.into());
103 }
104
105 CellIndex::new_unchecked(bits)
106 }
107
108 pub fn to_latlng(self, resolution: Resolution) -> LatLng {
116 Vec2d::from(self.coord).to_latlng(self.face, resolution.into(), false)
117 }
118
119 pub fn from_bits(
127 bits: u64,
128 resolution: Resolution,
129 base_cell: BaseCell,
130 ) -> (Self, bool) {
131 let mut fijk = Self::from(base_cell);
132 let possible_overage = base_cell.is_pentagon()
133 || (resolution != Resolution::Zero || fijk.coord != ZERO);
134
135 for res in Resolution::range(Resolution::One, resolution) {
136 if res.is_class3() {
137 fijk.coord = fijk.coord.down_aperture7::<{ CCW }>();
139 } else {
140 fijk.coord = fijk.coord.down_aperture7::<{ CW }>();
142 }
143
144 let direction =
146 Direction::new_unchecked(bits::get_direction(bits, res));
147 fijk.coord = fijk.coord.neighbor(direction);
148 }
149
150 (fijk, possible_overage)
151 }
152
153 pub fn adjust_overage_class2<const IS_SUBSTRATE: bool>(
169 &mut self,
170 class2_res: ExtendedResolution,
171 is_pent4: bool,
172 ) -> Overage {
173 let class2_res = usize::from(class2_res);
174 let factor = if IS_SUBSTRATE { 3 } else { 1 };
175 let face = usize::from(self.face);
176 let dimension = self.coord.i() + self.coord.j() + self.coord.k();
177
178 let max_dim = MAX_DIM_BY_CII_RES[class2_res] * factor;
180
181 if IS_SUBSTRATE && dimension == max_dim {
183 return Overage::FaceEdge;
184 }
185
186 if dimension > max_dim {
187 let orientation = if self.coord.k() > 0 {
188 if self.coord.j() > 0 {
189 face::NEIGHBORS[face][face::JK]
190 } else {
191 if is_pent4 {
193 let origin = CoordIJK::new(max_dim, 0, 0);
196 let tmp = (self.coord - origin).rotate60::<{ CW }>();
197 self.coord = tmp + origin;
199 }
200 face::NEIGHBORS[face][face::KI]
201 }
202 } else {
203 face::NEIGHBORS[face][face::IJ]
204 };
205 self.face = orientation.face;
206
207 for _ in 0..orientation.ccw_rot60 {
209 self.coord = self.coord.rotate60::<{ CCW }>();
210 }
211
212 let mut trans_vec = orientation.translate;
213 let unit_scale = UNIT_SCALE_BY_CII_RES[class2_res] * factor;
214 trans_vec *= unit_scale;
215 self.coord = (self.coord + trans_vec).normalize();
216
217 if IS_SUBSTRATE
219 && self.coord.i() + self.coord.j() + self.coord.k() == max_dim
220 {
221 return Overage::FaceEdge;
222 }
223 return Overage::NewFace;
224 }
225
226 Overage::None
227 }
228
229 pub fn adjust_pentagon_vertex_overage(
237 &mut self,
238 resolution: ExtendedResolution,
239 ) {
240 while self.adjust_overage_class2::<true>(resolution, false)
241 == Overage::NewFace
242 {}
243 }
244
245 pub fn pentagon_boundary(
254 &self,
255 resolution: Resolution,
256 start: Vertex,
257 length: u8,
258 ) -> Boundary {
259 let mut boundary = Boundary::new();
260 let start = u8::from(start);
261 let mut center = *self;
262 let mut vertices = [Self::default(); NUM_PENT_VERTS as usize];
263 let adjusted_resolution = center.vertices(resolution, &mut vertices);
264
265 let additional_iteration = u8::from(length == NUM_PENT_VERTS);
268
269 let mut last_fijk = Self::default();
273 for vert in start..(start + length + additional_iteration) {
274 let mut fijk: Self = vertices[usize::from(vert % NUM_PENT_VERTS)];
275 fijk.adjust_pentagon_vertex_overage(adjusted_resolution);
276
277 if resolution.is_class3() && vert > start {
282 let mut tmp_fijk = fijk;
284
285 let orig2d0 = Vec2d::from(last_fijk.coord);
286 let current_to_last_dir: u8 =
287 get_adjacent_face_dir(tmp_fijk.face, last_fijk.face);
288
289 let fijk_orientation: &FaceOrientIJK = &face::NEIGHBORS
290 [usize::from(tmp_fijk.face)]
291 [usize::from(current_to_last_dir)];
292
293 tmp_fijk.face = fijk_orientation.face;
294
295 for _ in 0..fijk_orientation.ccw_rot60 {
297 tmp_fijk.coord = tmp_fijk.coord.rotate60::<{ CCW }>();
298 }
299 let mut trans_vec = fijk_orientation.translate;
300 trans_vec *=
301 UNIT_SCALE_BY_CII_RES[usize::from(adjusted_resolution)] * 3;
302 tmp_fijk.coord = (tmp_fijk.coord + trans_vec).normalize();
303
304 let orig2d1 = Vec2d::from(tmp_fijk.coord);
305
306 let max_dim = f64::from(
308 MAX_DIM_BY_CII_RES[usize::from(adjusted_resolution)],
309 );
310 let v0 = Vec2d::new(3.0 * max_dim, 0.0);
311 let v1 = Vec2d::new(-1.5 * max_dim, 3.0 * SQRT3_2 * max_dim);
312 let v2 = Vec2d::new(-1.5 * max_dim, -3.0 * SQRT3_2 * max_dim);
313
314 let (edge0, edge1) = match usize::from(get_adjacent_face_dir(
315 tmp_fijk.face,
316 fijk.face,
317 )) {
318 face::IJ => (v0, v1),
319 face::JK => (v1, v2),
320 face::KI => (v2, v0),
321 _ => unreachable!("invalid face direction"),
322 };
323
324 let intersection =
327 Vec2d::intersection((orig2d0, orig2d1), (edge0, edge1));
328 boundary.push(intersection.to_latlng(
329 tmp_fijk.face,
330 adjusted_resolution,
331 true,
332 ));
333 }
334
335 if vert < start + NUM_PENT_VERTS {
339 boundary.push(Vec2d::from(fijk.coord).to_latlng(
340 fijk.face,
341 adjusted_resolution,
342 true,
343 ));
344 }
345
346 last_fijk = fijk;
347 }
348
349 boundary
350 }
351
352 pub fn hexagon_boundary(
361 &self,
362 resolution: Resolution,
363 start: Vertex,
364 length: u8,
365 ) -> Boundary {
366 let mut boundary = Boundary::new();
367 let start = u8::from(start);
368 let mut center = *self;
369 let mut vertices = [Self::default(); NUM_HEX_VERTS as usize];
370 let adjusted_resolution = center.vertices(resolution, &mut vertices);
371
372 let additional_iteration = u8::from(length == NUM_HEX_VERTS);
375
376 let mut last_face = usize::MAX;
381 let mut last_overage = Overage::None;
382 for vert in start..(start + length + additional_iteration) {
383 let v = usize::from(vert % NUM_HEX_VERTS);
384 let mut fijk = vertices[v];
385 let overage =
386 fijk.adjust_overage_class2::<true>(adjusted_resolution, false);
387
388 if resolution.is_class3()
399 && vert > start
400 && usize::from(fijk.face) != last_face
401 && last_overage != Overage::FaceEdge
402 {
403 let last_v: usize = (v + 5) % usize::from(NUM_HEX_VERTS);
405 let orig2d0 = Vec2d::from(vertices[last_v].coord);
406 let orig2d1 = Vec2d::from(vertices[v].coord);
407
408 let max_dim = f64::from(
410 MAX_DIM_BY_CII_RES[usize::from(adjusted_resolution)],
411 );
412 let v0 = Vec2d::new(3.0 * max_dim, 0.0);
413 let v1 = Vec2d::new(-1.5 * max_dim, 3.0 * SQRT3_2 * max_dim);
414 let v2 = Vec2d::new(-1.5 * max_dim, -3.0 * SQRT3_2 * max_dim);
415
416 let face2 = if last_face == usize::from(center.face) {
417 fijk.face
418 } else {
419 Face::new_unchecked(last_face)
420 };
421 let (edge0, edge1) = match usize::from(get_adjacent_face_dir(
422 center.face,
423 face2,
424 )) {
425 face::IJ => (v0, v1),
426 face::JK => (v1, v2),
427 face::KI => (v2, v0),
428 _ => unreachable!("invalid adjacent face direction"),
429 };
430
431 let intersection =
433 Vec2d::intersection((orig2d0, orig2d1), (edge0, edge1));
434 let is_intersection_at_vertex =
438 orig2d0 == intersection || orig2d1 == intersection;
439 if !is_intersection_at_vertex {
440 boundary.push(intersection.to_latlng(
441 center.face,
442 adjusted_resolution,
443 true,
444 ));
445 }
446 }
447
448 if vert < start + NUM_HEX_VERTS {
453 boundary.push(Vec2d::from(fijk.coord).to_latlng(
454 fijk.face,
455 adjusted_resolution,
456 true,
457 ));
458 }
459
460 last_face = fijk.face.into();
461 last_overage = overage;
462 }
463
464 boundary
465 }
466
467 pub fn vertices(
475 &mut self,
476 resolution: Resolution,
477 vertices: &mut [Self],
478 ) -> ExtendedResolution {
479 const VERTS_CII: [CoordIJK; 6] = [
485 CoordIJK::new(2, 1, 0),
486 CoordIJK::new(1, 2, 0),
487 CoordIJK::new(0, 2, 1),
488 CoordIJK::new(0, 1, 2),
489 CoordIJK::new(1, 0, 2),
490 CoordIJK::new(2, 0, 1),
491 ];
492
493 const VERTS_CIII: [CoordIJK; 6] = [
499 CoordIJK::new(5, 4, 0),
500 CoordIJK::new(1, 5, 0),
501 CoordIJK::new(0, 5, 4),
502 CoordIJK::new(0, 1, 5),
503 CoordIJK::new(4, 0, 5),
504 CoordIJK::new(5, 0, 1),
505 ];
506
507 self.coord = self.coord.down_aperture3::<{ CCW }>();
509 self.coord = self.coord.down_aperture3::<{ CW }>();
510
511 let (verts, adjusted_resolution) = if resolution.is_class3() {
514 self.coord = self.coord.down_aperture7::<{ CW }>();
515 (&VERTS_CIII, ExtendedResolution::down(resolution))
516 } else {
517 (&VERTS_CII, resolution.into())
518 };
519
520 for (i, vertex) in vertices.iter_mut().enumerate() {
525 vertex.face = self.face;
526 vertex.coord = (self.coord + verts[i]).normalize();
527 }
528
529 adjusted_resolution
530 }
531}
532
533#[allow(
541 clippy::inline_always,
542 reason = "4-5% boost, up to 13% at resolution 1."
543)]
544#[inline(always)]
545fn directions_bits_from_ijk(
546 mut ijk: CoordIJK,
547 bits: &mut u64,
548 resolution: Resolution,
549) -> CoordIJK {
550 for res in Resolution::range(Resolution::One, resolution).rev() {
551 let last_ijk = ijk;
552 let last_center = if res.is_class3() {
553 ijk = ijk.up_aperture7::<{ CCW }>();
555 ijk.down_aperture7::<{ CCW }>()
556 } else {
557 ijk = ijk.up_aperture7::<{ CW }>();
559 ijk.down_aperture7::<{ CW }>()
560 };
561
562 let diff = (last_ijk - last_center).normalize();
563 let direction = Direction::try_from(diff).expect("unit IJK coordinate");
564 *bits = bits::set_direction(*bits, direction.into(), res);
566 }
567
568 ijk
569}
570
571#[derive(Debug, Clone, Copy, Eq, PartialEq)]
575pub enum Overage {
576 None,
578 FaceEdge,
580 NewFace,
582}
583
584fn get_adjacent_face_dir(i: Face, j: Face) -> u8 {
587 ((ADJACENT_FACE_DIR[usize::from(i)] >> (usize::from(j) * 3)) & 0b111) as u8
588}
589
590macro_rules! adjacent_face_dir {
598 (central = $central:literal, IJ = $ij:literal, KI = $ki:literal, JK = $jk:literal) => {
599 !(0 | (0b111 << (3 * $central))
600 | (0b110 << (3 * $ij))
601 | (0b101 << (3 * $ki))
602 | (0b100 << (3 * $jk)))
603 };
604}
605
606#[rustfmt::skip]
609static ADJACENT_FACE_DIR: [u64; NUM_ICOSA_FACES] = [
610 adjacent_face_dir!(central = 0, IJ = 4, KI = 1, JK = 5), adjacent_face_dir!(central = 1, IJ = 0, KI = 2, JK = 6), adjacent_face_dir!(central = 2, IJ = 1, KI = 3, JK = 7), adjacent_face_dir!(central = 3, IJ = 2, KI = 4, JK = 8), adjacent_face_dir!(central = 4, IJ = 3, KI = 0, JK = 9), adjacent_face_dir!(central = 5, IJ = 10, KI = 14, JK = 0), adjacent_face_dir!(central = 6, IJ = 11, KI = 10, JK = 1), adjacent_face_dir!(central = 7, IJ = 12, KI = 11, JK = 2), adjacent_face_dir!(central = 8, IJ = 13, KI = 12, JK = 3), adjacent_face_dir!(central = 9, IJ = 14, KI = 13, JK = 4), adjacent_face_dir!(central = 10, IJ = 5, KI = 6, JK = 15), adjacent_face_dir!(central = 11, IJ = 6, KI = 7, JK = 16), adjacent_face_dir!(central = 12, IJ = 7, KI = 8, JK = 17), adjacent_face_dir!(central = 13, IJ = 8, KI = 9, JK = 18), adjacent_face_dir!(central = 14, IJ = 9, KI = 5, JK = 19), adjacent_face_dir!(central = 15, IJ = 16, KI = 19, JK = 10), adjacent_face_dir!(central = 16, IJ = 17, KI = 15, JK = 11), adjacent_face_dir!(central = 17, IJ = 18, KI = 16, JK = 12), adjacent_face_dir!(central = 18, IJ = 19, KI = 17, JK = 13), adjacent_face_dir!(central = 19, IJ = 15, KI = 18, JK = 14), ];
631
632#[rustfmt::skip]
636static MAX_DIM_BY_CII_RES: &[i32] = &[
637 2, -1, 14, -1, 98, -1, 686, -1, 4802, -1, 33614, -1, 235298, -1, 1647086, -1, 11529602, ];
655
656#[rustfmt::skip]
660static UNIT_SCALE_BY_CII_RES: &[i32] = &[
661 1, -1, 7, -1, 49, -1, 343, -1, 2401, -1, 16807, -1, 117649, -1, 823543, -1, 5764801, ];
679
680#[derive(Clone, Copy)]
684pub struct Rotation {
685 pub base_cell: BaseCell,
687 pub count: u8,
689}
690
691macro_rules! bcr {
693 ($base_cell:literal, $rotation:literal) => {
694 Rotation {
695 base_cell: BaseCell::new_unchecked($base_cell),
696 count: $rotation,
697 }
698 };
699}
700
701#[rustfmt::skip]
703const FACE_IJK_BASE_CELLS: [[[[Rotation; 3]; 3]; 3]; NUM_ICOSA_FACES] = [
704 [
705 [
706 [bcr!(16, 0), bcr!(18, 0), bcr!(24, 0)],
707 [bcr!(33, 0), bcr!(30, 0), bcr!(32, 3)],
708 [bcr!(49, 1), bcr!(48, 3), bcr!(50, 3)],
709 ], [
710 [bcr!(8, 0), bcr!(5, 5), bcr!(10, 5)],
711 [bcr!(22, 0), bcr!(16, 0), bcr!(18, 0)],
712 [bcr!(41, 1), bcr!(33, 0), bcr!(30, 0)],
713 ], [
714 [bcr!(4, 0), bcr!(0, 5), bcr!(2, 5)],
715 [bcr!(15, 1), bcr!(8, 0), bcr!(5, 5)],
716 [bcr!(31, 1), bcr!(22, 0), bcr!(16, 0)],
717 ],
718 ], [
719 [
720 [bcr!(2, 0), bcr!(6, 0), bcr!(14, 0)],
721 [bcr!(10, 0), bcr!(11, 0), bcr!(17, 3)],
722 [bcr!(24, 1), bcr!(23, 3), bcr!(25, 3)],
723 ], [
724 [bcr!(0, 0), bcr!(1, 5), bcr!(9, 5)],
725 [bcr!(5, 0), bcr!(2, 0), bcr!(6, 0)],
726 [bcr!(18, 1), bcr!(10, 0), bcr!(11, 0)],
727 ], [
728 [bcr!(4, 1), bcr!(3, 5), bcr!(7, 5)],
729 [bcr!(8, 1), bcr!(0, 0), bcr!(1, 5)],
730 [bcr!(16, 1), bcr!(5, 0), bcr!(2, 0)],
731 ],
732 ], [
733 [
734 [bcr!(7, 0), bcr!(21, 0), bcr!(38, 0)],
735 [bcr!(9, 0), bcr!(19, 0), bcr!(34, 3)],
736 [bcr!(14, 1), bcr!(20, 3), bcr!(36, 3)],
737 ], [
738 [bcr!(3, 0), bcr!(13, 5), bcr!(29, 5)],
739 [bcr!(1, 0), bcr!(7, 0), bcr!(21, 0)],
740 [bcr!(6, 1), bcr!(9, 0), bcr!(19, 0)],
741 ], [
742 [bcr!(4, 2), bcr!(12, 5), bcr!(26, 5)],
743 [bcr!(0, 1), bcr!(3, 0), bcr!(13, 5)],
744 [bcr!(2, 1), bcr!(1, 0), bcr!(7, 0)],
745 ]
746 ], [
747 [
748 [bcr!(26, 0), bcr!(42, 0), bcr!(58, 0)],
749 [bcr!(29, 0), bcr!(43, 0), bcr!(62, 3)],
750 [bcr!(38, 1), bcr!(47, 3), bcr!(64, 3)],
751 ], [
752 [bcr!(12, 0), bcr!(28, 5), bcr!(44, 5)],
753 [bcr!(13, 0), bcr!(26, 0), bcr!(42, 0)],
754 [bcr!(21, 1), bcr!(29, 0), bcr!(43, 0)],
755 ], [
756 [bcr!(4, 3), bcr!(15, 5), bcr!(31, 5)],
757 [bcr!(3, 1), bcr!(12, 0), bcr!(28, 5)],
758 [bcr!(7, 1), bcr!(13, 0), bcr!(26, 0)],
759 ]
760 ], [
761 [
762 [bcr!(31, 0), bcr!(41, 0), bcr!(49, 0)],
763 [bcr!(44, 0), bcr!(53, 0), bcr!(61, 3)],
764 [bcr!(58, 1), bcr!(65, 3), bcr!(75, 3)],
765 ], [
766 [bcr!(15, 0), bcr!(22, 5), bcr!(33, 5)],
767 [bcr!(28, 0), bcr!(31, 0), bcr!(41, 0)],
768 [bcr!(42, 1), bcr!(44, 0), bcr!(53, 0)],
769 ], [
770 [bcr!(4, 4), bcr!(8, 5), bcr!(16, 5)],
771 [bcr!(12, 1), bcr!(15, 0), bcr!(22, 5)],
772 [bcr!(26, 1), bcr!(28, 0), bcr!(31, 0)],
773 ]
774 ], [
775 [
776 [bcr!(50, 0), bcr!(48, 0), bcr!(49, 3)],
777 [bcr!(32, 0), bcr!(30, 3), bcr!(33, 3)],
778 [bcr!(24, 3), bcr!(18, 3), bcr!(16, 3)],
779 ], [
780 [bcr!(70, 0), bcr!(67, 0), bcr!(66, 3)],
781 [bcr!(52, 3), bcr!(50, 0), bcr!(48, 0)],
782 [bcr!(37, 3), bcr!(32, 0), bcr!(30, 3)],
783 ], [
784 [bcr!(83, 0), bcr!(87, 3), bcr!(85, 3)],
785 [bcr!(74, 3), bcr!(70, 0), bcr!(67, 0)],
786 [bcr!(57, 1), bcr!(52, 3), bcr!(50, 0)],
787 ]
788 ], [
789 [
790 [bcr!(25, 0), bcr!(23, 0), bcr!(24, 3)],
791 [bcr!(17, 0), bcr!(11, 3), bcr!(10, 3)],
792 [bcr!(14, 3), bcr!(6, 3), bcr!(2, 3)],
793 ], [
794 [bcr!(45, 0), bcr!(39, 0), bcr!(37, 3)],
795 [bcr!(35, 3), bcr!(25, 0), bcr!(23, 0)],
796 [bcr!(27, 3), bcr!(17, 0), bcr!(11, 3)],
797 ], [
798 [bcr!(63, 0), bcr!(59, 3), bcr!(57, 3)],
799 [bcr!(56, 3), bcr!(45, 0), bcr!(39, 0)],
800 [bcr!(46, 3), bcr!(35, 3), bcr!(25, 0)],
801 ]
802 ], [
803 [
804 [bcr!(36, 0), bcr!(20, 0), bcr!(14, 3)],
805 [bcr!(34, 0), bcr!(19, 3), bcr!(9, 3)],
806 [bcr!(38, 3), bcr!(21, 3), bcr!(7, 3)],
807 ], [
808 [bcr!(55, 0), bcr!(40, 0), bcr!(27, 3)],
809 [bcr!(54, 3), bcr!(36, 0), bcr!(20, 0)],
810 [bcr!(51, 3), bcr!(34, 0), bcr!(19, 3)],
811 ], [
812 [bcr!(72, 0), bcr!(60, 3), bcr!(46, 3)],
813 [bcr!(73, 3), bcr!(55, 0), bcr!(40, 0)],
814 [bcr!(71, 3), bcr!(54, 3), bcr!(36, 0)],
815 ]
816 ], [
817 [
818 [bcr!(64, 0), bcr!(47, 0), bcr!(38, 3)],
819 [bcr!(62, 0), bcr!(43, 3), bcr!(29, 3)],
820 [bcr!(58, 3), bcr!(42, 3), bcr!(26, 3)],
821 ], [
822 [bcr!(84, 0), bcr!(69, 0), bcr!(51, 3)],
823 [bcr!(82, 3), bcr!(64, 0), bcr!(47, 0)],
824 [bcr!(76, 3), bcr!(62, 0), bcr!(43, 3)],
825 ], [
826 [bcr!(97, 0), bcr!(89, 3), bcr!(71, 3)],
827 [bcr!(98, 3), bcr!(84, 0), bcr!(69, 0)],
828 [bcr!(96, 3), bcr!(82, 3), bcr!(64, 0)],
829 ]
830 ], [
831 [
832 [bcr!(75, 0), bcr!(65, 0), bcr!(58, 3)],
833 [bcr!(61, 0), bcr!(53, 3), bcr!(44, 3)],
834 [bcr!(49, 3), bcr!(41, 3), bcr!(31, 3)],
835 ], [
836 [bcr!(94, 0), bcr!(86, 0), bcr!(76, 3)],
837 [bcr!(81, 3), bcr!(75, 0), bcr!(65, 0)],
838 [bcr!(66, 3), bcr!(61, 0), bcr!(53, 3)],
839 ], [
840 [bcr!(107, 0), bcr!(104, 3), bcr!(96, 3)],
841 [bcr!(101, 3), bcr!(94, 0), bcr!(86, 0)],
842 [bcr!(85, 3), bcr!(81, 3), bcr!(75, 0)],
843 ]
844 ], [
845 [
846 [bcr!(57, 0), bcr!(59, 0), bcr!(63, 3)],
847 [bcr!(74, 0), bcr!(78, 3), bcr!(79, 3)],
848 [bcr!(83, 3), bcr!(92, 3), bcr!(95, 3)],
849 ], [
850 [bcr!(37, 0), bcr!(39, 3), bcr!(45, 3)],
851 [bcr!(52, 0), bcr!(57, 0), bcr!(59, 0)],
852 [bcr!(70, 3), bcr!(74, 0), bcr!(78, 3)],
853 ], [
854 [bcr!(24, 0), bcr!(23, 3), bcr!(25, 3)],
855 [bcr!(32, 3), bcr!(37, 0), bcr!(39, 3)],
856 [bcr!(50, 3), bcr!(52, 0), bcr!(57, 0)],
857 ]
858 ], [
859 [
860 [bcr!(46, 0), bcr!(60, 0), bcr!(72, 3)],
861 [bcr!(56, 0), bcr!(68, 3), bcr!(80, 3)],
862 [bcr!(63, 3), bcr!(77, 3), bcr!(90, 3)],
863 ], [
864 [bcr!(27, 0), bcr!(40, 3), bcr!(55, 3)],
865 [bcr!(35, 0), bcr!(46, 0), bcr!(60, 0)],
866 [bcr!(45, 3), bcr!(56, 0), bcr!(68, 3)],
867 ], [
868 [bcr!(14, 0), bcr!(20, 3), bcr!(36, 3)],
869 [bcr!(17, 3), bcr!(27, 0), bcr!(40, 3)],
870 [bcr!(25, 3), bcr!(35, 0), bcr!(46, 0)],
871 ]
872 ], [
873 [
874 [bcr!(71, 0), bcr!(89, 0), bcr!(97, 3)],
875 [bcr!(73, 0), bcr!(91, 3), bcr!(103, 3)],
876 [bcr!(72, 3), bcr!(88, 3), bcr!(105, 3)],
877 ], [
878 [bcr!(51, 0), bcr!(69, 3), bcr!(84, 3)],
879 [bcr!(54, 0), bcr!(71, 0), bcr!(89, 0)],
880 [bcr!(55, 3), bcr!(73, 0), bcr!(91, 3)],
881 ], [
882 [bcr!(38, 0), bcr!(47, 3), bcr!(64, 3)],
883 [bcr!(34, 3), bcr!(51, 0), bcr!(69, 3)],
884 [bcr!(36, 3), bcr!(54, 0), bcr!(71, 0)],
885 ]
886 ], [
887 [
888 [bcr!(96, 0), bcr!(104, 0), bcr!(107, 3)],
889 [bcr!(98, 0), bcr!(110, 3), bcr!(115, 3)],
890 [bcr!(97, 3), bcr!(111, 3), bcr!(119, 3)],
891 ], [
892 [bcr!(76, 0), bcr!(86, 3), bcr!(94, 3)],
893 [bcr!(82, 0), bcr!(96, 0), bcr!(104, 0)],
894 [bcr!(84, 3), bcr!(98, 0), bcr!(110, 3)],
895 ], [
896 [bcr!(58, 0), bcr!(65, 3), bcr!(75, 3)],
897 [bcr!(62, 3), bcr!(76, 0), bcr!(86, 3)],
898 [bcr!(64, 3), bcr!(82, 0), bcr!(96, 0)],
899 ]
900 ], [
901 [
902 [bcr!(85, 0), bcr!(87, 0), bcr!(83, 3)],
903 [bcr!(101, 0), bcr!(102, 3), bcr!(100, 3)],
904 [bcr!(107, 3), bcr!(112, 3), bcr!(114, 3)],
905 ], [
906 [bcr!(66, 0), bcr!(67, 3), bcr!(70, 3)],
907 [bcr!(81, 0), bcr!(85, 0), bcr!(87, 0)],
908 [bcr!(94, 3), bcr!(101, 0), bcr!(102, 3)],
909 ], [
910 [bcr!(49, 0), bcr!(48, 3), bcr!(50, 3)],
911 [bcr!(61, 3), bcr!(66, 0), bcr!(67, 3)],
912 [bcr!(75, 3), bcr!(81, 0), bcr!(85, 0)],
913 ]
914 ], [
915 [
916 [bcr!(95, 0), bcr!(92, 0), bcr!(83, 0)],
917 [bcr!(79, 0), bcr!(78, 0), bcr!(74, 3)],
918 [bcr!(63, 1), bcr!(59, 3), bcr!(57, 3)],
919 ], [
920 [bcr!(109, 0), bcr!(108, 0), bcr!(100, 5)],
921 [bcr!(93, 1), bcr!(95, 0), bcr!(92, 0)],
922 [bcr!(77, 1), bcr!(79, 0), bcr!(78, 0)],
923 ], [
924 [bcr!(117, 4), bcr!(118, 5), bcr!(114, 5)],
925 [bcr!(106, 1), bcr!(109, 0), bcr!(108, 0)],
926 [bcr!(90, 1), bcr!(93, 1), bcr!(95, 0)],
927 ]
928 ], [
929 [
930 [bcr!(90, 0), bcr!(77, 0), bcr!(63, 0)],
931 [bcr!(80, 0), bcr!(68, 0), bcr!(56, 3)],
932 [bcr!(72, 1), bcr!(60, 3), bcr!(46, 3)],
933 ], [
934 [bcr!(106, 0), bcr!(93, 0), bcr!(79, 5)],
935 [bcr!(99, 1), bcr!(90, 0), bcr!(77, 0)],
936 [bcr!(88, 1), bcr!(80, 0), bcr!(68, 0)],
937 ], [
938 [bcr!(117, 3), bcr!(109, 5), bcr!(95, 5)],
939 [bcr!(113, 1), bcr!(106, 0), bcr!(93, 0)],
940 [bcr!(105, 1), bcr!(99, 1), bcr!(90, 0)],
941 ]
942 ], [
943 [
944 [bcr!(105, 0), bcr!(88, 0), bcr!(72, 0)],
945 [bcr!(103, 0), bcr!(91, 0), bcr!(73, 3)],
946 [bcr!(97, 1), bcr!(89, 3), bcr!(71, 3)],
947 ], [
948 [bcr!(113, 0), bcr!(99, 0), bcr!(80, 5)],
949 [bcr!(116, 1), bcr!(105, 0), bcr!(88, 0)],
950 [bcr!(111, 1), bcr!(103, 0), bcr!(91, 0)],
951 ], [
952 [bcr!(117, 2), bcr!(106, 5), bcr!(90, 5)],
953 [bcr!(121, 1), bcr!(113, 0), bcr!(99, 0)],
954 [bcr!(119, 1), bcr!(116, 1), bcr!(105, 0)],
955 ]
956 ], [
957 [
958 [bcr!(119, 0), bcr!(111, 0), bcr!(97, 0)],
959 [bcr!(115, 0), bcr!(110, 0), bcr!(98, 3)],
960 [bcr!(107, 1), bcr!(104, 3), bcr!(96, 3)],
961 ], [
962 [bcr!(121, 0), bcr!(116, 0), bcr!(103, 5)],
963 [bcr!(120, 1), bcr!(119, 0), bcr!(111, 0)],
964 [bcr!(112, 1), bcr!(115, 0), bcr!(110, 0)],
965 ], [
966 [bcr!(117, 1), bcr!(113, 5), bcr!(105, 5)],
967 [bcr!(118, 1), bcr!(121, 0), bcr!(116, 0)],
968 [bcr!(114, 1), bcr!(120, 1), bcr!(119, 0)],
969 ]
970 ], [
971 [
972 [bcr!(114, 0), bcr!(112, 0), bcr!(107, 0)],
973 [bcr!(100, 0), bcr!(102, 0), bcr!(101, 3)],
974 [bcr!(83, 1), bcr!(87, 3), bcr!(85, 3)],
975 ], [
976 [bcr!(118, 0), bcr!(120, 0), bcr!(115, 5)],
977 [bcr!(108, 1), bcr!(114, 0), bcr!(112, 0)],
978 [bcr!(92, 1), bcr!(100, 0), bcr!(102, 0)],
979 ], [
980 [bcr!(117, 0), bcr!(121, 5), bcr!(119, 5)],
981 [bcr!(109, 1), bcr!(118, 0), bcr!(120, 0)],
982 [bcr!(95, 1), bcr!(108, 1), bcr!(114, 0)],
983 ]
984 ]
985];