1use crate::prelude::*;
3use crate::proj::BaseTriProjector;
4use crate::tri::{self, BaseRegion, BaseRegionType, TriSphere};
5use std::num::NonZero;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub struct HexSphere<Proj> {
15 kis: TriSphere<Proj>,
16}
17
18impl<Proj: Clone + BaseTriProjector> TriSphere<Proj> {
19 pub fn truncate(self) -> HexSphere<Proj> {
24 HexSphere {
25 kis: self.subdivide_edge(NonZero::new(3).unwrap()),
26 }
27 }
28}
29
30impl<Proj> HexSphere<Proj> {
31 pub fn new(kis: TriSphere<Proj>) -> Option<Self> {
37 if (kis.b() + 2 * kis.c()) % 3 == 0 {
38 Some(Self { kis })
39 } else {
40 None
41 }
42 }
43
44 pub fn kis(self) -> TriSphere<Proj> {
50 self.kis
51 }
52
53 const fn dual_num_divisions(&self) -> usize {
55 let b = self.kis.b() as usize;
56 let c = self.kis.c() as usize;
57 let dual_c = (b - c) / 3;
58 let dual_b = c + dual_c;
59 dual_b * (dual_b + dual_c) + dual_c * dual_c
60 }
61
62 fn num_faces_per_edge_region(&self) -> usize {
64 let b = self.kis.b() as usize;
65 let c = self.kis.c() as usize;
66 num_faces_on_edge(b, c + 1)
67 }
68
69 fn num_faces_per_interior_region(&self) -> usize {
71 let b = self.kis.b() as usize;
72 let c = self.kis.c() as usize;
73 let n = b - c;
74 if n == 0 {
75 (c % 3 == 0) as usize
76 } else {
77 num_faces_on_interior(c, n, n)
78 }
79 }
80
81 fn num_vertices_per_edge_region(&self) -> usize {
84 self.kis.num_vertices_per_edge_region() - self.num_faces_per_edge_region()
85 }
86
87 fn num_vertices_per_interior_region(&self) -> usize {
89 self.kis.num_vertices_per_interior_region() - self.num_faces_per_interior_region()
90 }
91}
92
93fn num_faces_on_edge(b: usize, d: usize) -> usize {
95 ((b - 1) * d + (b % 3) / 2) / 3
96}
97
98#[test]
99fn test_num_faces_on_edge() {
100 for b in 1..10 {
101 for d in 0..10 {
102 let mut count = 0;
103 for u in 1..b {
104 for v in 0..d {
105 if u % 3 == v % 3 {
106 count += 1;
107 }
108 }
109 }
110 assert_eq!(
111 num_faces_on_edge(b, d),
112 count,
113 "failed for b = {}, d = {}",
114 b,
115 d
116 );
117 }
118 }
119}
120
121fn num_faces_on_interior(k: usize, n: usize, d: usize) -> usize {
124 (d - 1) * (2 * n - d - 2) / 6 + ((k % 3 == 0) & (d % 3 != 1)) as usize
125}
126
127#[test]
128fn test_num_faces_on_interior() {
129 for k in 0..2 {
130 for n_3 in 1..10 {
131 let n = n_3 * 3;
132 for d in 1..n {
133 let mut count = 0;
134 for u in 1..n {
135 for v in 1..d {
136 if u + v < n && u % 3 == (v + k) % 3 {
137 count += 1;
138 }
139 }
140 }
141 assert_eq!(
142 num_faces_on_interior(k, n, d),
143 count,
144 "failed for k = {}, n = {}, d = {}",
145 k,
146 n,
147 d
148 );
149 }
150 }
151 }
152}
153
154impl<Proj: Eq + Clone + BaseTriProjector> crate::Sphere for HexSphere<Proj> {
155 type Face = Face<Proj>;
156 type Vertex = Vertex<Proj>;
157 type HalfEdge = HalfEdge<Proj>;
158
159 fn num_faces(&self) -> usize {
160 self.num_vertices() / 2 + 2
161 }
162
163 fn face(&self, index: usize) -> Face<Proj> {
164 self.faces().nth(index).expect("face index out of bounds")
166 }
167
168 fn faces(&self) -> impl Iterator<Item = Face<Proj>> {
169 FaceIter {
170 sphere: self.clone(),
171 region: self.kis.base().first_region(),
172 u: 0,
173 u_end: self.kis.b(),
174 v: 0,
175 }
176 }
177
178 fn face_at(&self, point: [f64; 3]) -> Face<Proj> {
179 unsafe { Face::from_kis(self.kis.face_at(point)).unwrap_unchecked() }
180 }
181
182 fn num_vertices(&self) -> usize {
183 self.dual_num_divisions() * self.kis.base().num_faces()
184 }
185
186 fn vertex(&self, index: usize) -> Vertex<Proj> {
187 todo!()
188 }
189
190 fn vertices(&self) -> impl Iterator<Item = Vertex<Proj>> {
191 VertexIter {
192 sphere: self.clone(),
193 region: self.kis.base().first_region(),
194 u: 1,
195 u_end: self.kis.b(),
196 v: 0,
197 skip: false,
198 }
199 }
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
204pub struct Face<Proj> {
205 center: tri::Vertex<Proj>,
206}
207
208impl<Proj: Eq + Clone + BaseTriProjector> Face<Proj> {
209 pub fn from_center(center: tri::Vertex<Proj>) -> Option<Self> {
224 if center.sphere.b() % 3 != center.sphere.c() % 3 {
225 return None;
226 }
227 if center.u % 3 != center.adjusted_v() % 3 {
228 return None;
229 }
230 Some(Self { center })
231 }
232
233 pub fn from_kis(kis: tri::Face<Proj>) -> Option<Self> {
248 if kis.sphere.b() % 3 != kis.sphere.c() % 3 {
249 return None;
250 }
251 let adj_v = if !kis.region.ty().is_edge() {
252 kis.sphere.c()
253 } else {
254 0
255 };
256 let [u, v] = match ((kis.u_0 + 2 * (kis.v_0 + adj_v)) % 3, kis.boundary_along_v) {
257 (0, _) => [kis.u_0, kis.v_0],
258 (1, _) => [kis.u_0, kis.v_0 + 1],
259 (_, false) => [kis.u_0 + 1, kis.v_0],
260 (_, true) => [kis.u_0 - 1, kis.v_0 + 1],
261 };
262 Some(unsafe {
263 Self::from_center(tri::Vertex::new(kis.sphere, kis.region, u, v)).unwrap_unchecked()
264 })
265 }
266
267 pub fn sphere(&self) -> HexSphere<Proj> {
269 HexSphere {
270 kis: self.center.sphere.clone(),
271 }
272 }
273
274 pub fn center(self) -> tri::Vertex<Proj> {
276 self.center
277 }
278
279 pub fn is_hex(&self) -> bool {
281 self.center.as_base().is_none()
282 }
283}
284
285impl<Proj: Eq + Clone + BaseTriProjector> crate::Face for Face<Proj> {
286 type Vertex = Vertex<Proj>;
287 type HalfEdge = HalfEdge<Proj>;
288
289 fn index(&self) -> usize {
290 let b = self.center.sphere.b() as usize;
291 let c = self.center.sphere.c() as usize;
292 if self.center.region.ty().is_edge() {
293 self.sphere().base_face_index(self.center.region)
294 + num_faces_on_edge(b, self.center.v as usize)
295 + (self.center.u as usize).div_ceil(3)
296 } else if c < b {
297 self.sphere().base_face_index(self.center.region)
298 + num_faces_on_interior(c, b - c, self.center.v as usize)
299 + (self.center.u as usize).div_ceil(3)
300 } else {
301 self.sphere().base_face_index(self.center.region) + 1
302 }
303 }
304
305 fn area(&self) -> f64 {
306 crate::util::poly_area(self.vertices().map(|v| v.pos()))
307 }
308
309 fn num_sides(&self) -> usize {
310 if let Some(base) = self.center.as_base() {
311 base.degree()
312 } else {
313 6
314 }
315 }
316
317 fn side(&self, index: usize) -> HalfEdge<Proj> {
318 HalfEdge {
319 kis: self.center.outgoing(index).next(),
320 }
321 }
322}
323
324#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
326pub struct Vertex<Proj> {
327 kis: tri::Vertex<Proj>,
328}
329
330impl<Proj> Vertex<Proj> {
331 fn new(kis: tri::Vertex<Proj>) -> Self {
333 debug_assert_ne!(kis.u % 3, kis.adjusted_v() % 3);
334 Self { kis }
335 }
336}
337
338impl<Proj> tri::Vertex<Proj> {
339 fn adjusted_v(&self) -> u32 {
345 let mut v = self.v;
346 if !self.region.ty().is_edge() {
347 v += self.sphere.c();
348 }
349 v
350 }
351}
352
353impl<Proj: Clone> Vertex<Proj> {
354 pub fn sphere(&self) -> HexSphere<Proj> {
356 HexSphere {
357 kis: self.kis.sphere.clone(),
358 }
359 }
360
361 pub fn kis(self) -> tri::Vertex<Proj> {
363 self.kis
364 }
365}
366
367impl<Proj: Eq + Clone + BaseTriProjector> crate::Vertex for Vertex<Proj> {
368 type Face = Face<Proj>;
369 type HalfEdge = HalfEdge<Proj>;
370
371 fn index(&self) -> usize {
372 let b = self.kis.sphere.b() as usize;
373 let c = self.kis.sphere.c() as usize;
374 if self.kis.region.ty().is_edge() {
375 self.sphere().base_vertex_index(self.kis.region) + self.kis.v as usize * (b - 1)
376 - num_faces_on_edge(b, self.kis.v as usize)
377 + (self.kis.u as usize * 2 - 1 - (self.kis.v % 3 == 1) as usize) / 3
378 } else if c < b {
379 let n = b - c;
380 self.sphere().base_vertex_index(self.kis.region)
381 + (self.kis.v as usize - 1) * (2 * n - self.kis.v as usize - 2) / 2
382 - num_faces_on_interior(c, n, self.kis.v as usize)
383 + (self.kis.u as usize * 2 - 1 - ((self.kis.v as usize + c) % 3 == 1) as usize) / 3
384 } else {
385 self.sphere().base_vertex_index(self.kis.region)
386 }
387 }
388
389 fn pos(&self) -> [f64; 3] {
390 self.kis.pos()
391 }
392
393 fn degree(&self) -> usize {
394 3
395 }
396
397 fn outgoing(&self, index: usize) -> HalfEdge<Proj> {
398 assert!(index < 3, "index out of bounds");
399 let phase = (self.kis.u + 2 * self.kis.adjusted_v()) % 3;
400 debug_assert_ne!(phase, 0);
401 HalfEdge {
402 kis: tri::HalfEdge::new(
403 self.kis.sphere.clone(),
404 self.kis.region,
405 self.kis.u,
406 self.kis.v,
407 tri::HalfEdgeDir::from_index(2 * index + phase as usize - 1),
408 ),
409 }
410 }
411}
412
413#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
415pub struct HalfEdge<Proj> {
416 kis: tri::HalfEdge<Proj>,
417}
418
419impl<Proj> HalfEdge<Proj> {
420 pub fn kis(self) -> tri::HalfEdge<Proj> {
422 self.kis
423 }
424}
425
426impl<Proj: Eq + Clone + BaseTriProjector> crate::HalfEdge for HalfEdge<Proj> {
427 type Face = Face<Proj>;
428 type Vertex = Vertex<Proj>;
429
430 fn side_index(&self) -> usize {
431 self.kis.prev().outgoing_index()
432 }
433
434 fn length(&self) -> f64 {
435 self.kis.length()
436 }
437
438 fn angle(&self) -> f64 {
439 let v_a = self.prev().start().pos();
440 let v_b = self.start().pos();
441 let v_c = self.next().start().pos();
442 crate::util::angle(v_a, v_b, v_c)
443 }
444
445 fn inside(&self) -> Face<Proj> {
446 Face {
447 center: self.kis.prev().start(),
448 }
449 }
450
451 fn start(&self) -> Vertex<Proj> {
452 Vertex {
453 kis: self.kis.start(),
454 }
455 }
456
457 fn complement(&self) -> Self {
458 Self {
459 kis: self.kis.complement(),
460 }
461 }
462
463 fn prev(&self) -> Self {
464 Self {
465 kis: self.kis.prev().complement().prev(),
466 }
467 }
468
469 fn next(&self) -> Self {
470 Self {
471 kis: self.kis.next().complement().next(),
472 }
473 }
474}
475
476impl<Proj> HexSphere<Proj> {
477 fn base_face_index(&self, region: BaseRegion) -> usize {
480 let face = region.owner();
481 let num_owned_vertices_before = face.num_owned_vertices_before()
482 + (face.owns_vertex_1() && region.ty() > BaseRegionType::Edge0) as usize;
483 let num_edge_regions_before =
484 face.num_owned_edges_before() + (region.ty() > BaseRegionType::Edge0) as usize;
485 let num_interior_regions_before =
486 face.index() + (region.ty() > BaseRegionType::Interior) as usize;
487 num_owned_vertices_before
488 + num_edge_regions_before * self.num_faces_per_edge_region()
489 + num_interior_regions_before * self.num_faces_per_interior_region()
490 }
491
492 fn base_vertex_index(&self, region: BaseRegion) -> usize {
494 let face = region.owner();
495 let num_edge_regions_before =
496 face.num_owned_edges_before() + (region.ty() > BaseRegionType::Edge0) as usize;
497 let num_interior_regions_before =
498 face.index() + (region.ty() > BaseRegionType::Interior) as usize;
499 num_edge_regions_before * self.num_vertices_per_edge_region()
500 + num_interior_regions_before * self.num_vertices_per_interior_region()
501 }
502}
503
504impl<Proj> HexSphere<Proj> {
505 fn faces_from(self, region: BaseRegion) -> FaceIter<Proj> {
507 let b = self.kis.b();
508 let c = self.kis.c();
509 if region.ty().is_edge() {
510 FaceIter {
511 sphere: self,
512 region,
513 u: 3,
514 u_end: b,
515 v: 0,
516 }
517 } else if c < b {
518 let n = b - c;
519 FaceIter {
520 sphere: self,
521 region,
522 u: 1 + c % 3,
523 u_end: n - 1,
524 v: 1,
525 }
526 } else {
527 FaceIter {
530 sphere: self,
531 region,
532 u: c % 3,
533 u_end: 1,
534 v: 0,
535 }
536 }
537 }
538}
539
540#[derive(Clone, Debug)]
542pub struct FaceIter<Proj> {
543 sphere: HexSphere<Proj>,
544 region: BaseRegion,
545 u: u32,
546 u_end: u32,
547 v: u32,
548}
549
550impl<Proj: Eq + Clone + BaseTriProjector> Iterator for FaceIter<Proj> {
551 type Item = Face<Proj>;
552 fn next(&mut self) -> Option<Face<Proj>> {
553 loop {
554 if self.u < self.u_end {
555 let res = unsafe {
556 Face::from_center(tri::Vertex {
557 sphere: self.sphere.kis.clone(),
558 region: self.region,
559 u: self.u,
560 v: self.v,
561 })
562 .unwrap_unchecked()
563 };
564 self.u += 3;
565 return Some(res);
566 } else if self.region.ty().is_edge() {
567 if self.v < self.sphere.kis.c() {
568 self.v += 1;
569 self.u = 1 + (self.v + 2) % 3;
570 continue;
571 } else if self.u <= self.u_end
572 && self.region.ty() == BaseRegionType::Edge0
573 && self.region.owner().owns_vertex_1()
574 {
575 let res = unsafe {
576 Face::from_center(tri::Vertex {
577 sphere: self.sphere.kis.clone(),
578 region: self.region,
579 u: self.u,
580 v: self.v,
581 })
582 .unwrap_unchecked()
583 };
584 self.u += 3;
585 return Some(res);
586 }
587 } else {
588 let n = self.sphere.kis.b() - self.sphere.kis.c();
589 if self.v + 1 < n {
590 self.v += 1;
591 self.u = 1 + (self.v + self.sphere.kis.c() + 2) % 3;
592 self.u_end = n - self.v;
593 continue;
594 }
595 }
596 if let Some(region) = self.sphere.kis.base().next_region(self.region) {
597 *self = self.sphere.clone().faces_from(region);
598 continue;
599 } else {
600 return None;
601 }
602 }
603 }
604}
605
606impl<Proj: Eq + Clone + BaseTriProjector> HexSphere<Proj> {
607 fn vertices_from(self, region: BaseRegion) -> VertexIter<Proj> {
609 let b = self.kis.b();
610 let c = self.kis.c();
611 if region.ty().is_edge() {
612 VertexIter {
613 sphere: self,
614 region,
615 u: 1,
616 u_end: b,
617 v: 0,
618 skip: false,
619 }
620 } else if c < b {
621 let n = b - c;
622 VertexIter {
623 sphere: self,
624 region,
625 u: 1 + (c % 3 == 0) as u32,
626 u_end: n.saturating_sub(1),
627 v: 1,
628 skip: c % 3 == 1,
629 }
630 } else {
631 VertexIter {
634 sphere: self,
635 region,
636 u: (c % 3 == 0) as u32,
637 u_end: 1,
638 v: 0,
639 skip: c % 3 == 2,
640 }
641 }
642 }
643}
644
645#[derive(Clone, Debug)]
647pub struct VertexIter<Proj> {
648 sphere: HexSphere<Proj>,
649 region: BaseRegion,
650 u: u32,
651 u_end: u32,
652 v: u32,
653 skip: bool,
654}
655
656impl<Proj: Eq + Clone + BaseTriProjector> Iterator for VertexIter<Proj> {
657 type Item = Vertex<Proj>;
658 fn next(&mut self) -> Option<Vertex<Proj>> {
659 loop {
660 if self.u < self.u_end {
661 let res = Vertex::new(tri::Vertex {
662 sphere: self.sphere.kis.clone(),
663 region: self.region,
664 u: self.u,
665 v: self.v,
666 });
667 self.u += 1;
668 self.u += self.skip as u32;
669 self.skip = !self.skip;
670 return Some(res);
671 } else if self.region.ty().is_edge() {
672 if self.v < self.sphere.kis.c() {
673 self.v += 1;
674 (self.u, self.skip) = match self.v % 3 {
675 0 => (1, false),
676 1 => (2, false),
677 _ => (1, true),
678 };
679 continue;
680 }
681 } else {
682 let n = self.sphere.kis.b() - self.sphere.kis.c();
683 if self.v + 1 < n {
684 self.v += 1;
685 self.u_end = n - self.v;
686 (self.u, self.skip) = match (self.v + self.sphere.kis.c()) % 3 {
687 0 => (1, false),
688 1 => (2, false),
689 _ => (1, true),
690 };
691 continue;
692 }
693 }
694 if let Some(region) = self.sphere.kis.base().next_region(self.region) {
695 *self = self.sphere.clone().vertices_from(region);
696 continue;
697 } else {
698 return None;
699 }
700 }
701 }
702}