lattice_graph/hex/shapes/
mod.rs

1//! Defines the shape and behaivour of coordinates in hex graph.
2
3use std::marker::PhantomData;
4
5use crate::{lattice_abstract::*, unreachable_debug_checked};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
8/// Point top Hex Direcion.
9pub enum AxisR {
10    NE = 0,
11    E = 1,
12    SE = 2,
13}
14
15impl Axis for AxisR {
16    const COUNT: usize = 3;
17    const DIRECTED: bool = false;
18    type Direction = AxisDR;
19
20    fn to_index(&self) -> usize {
21        match self {
22            AxisR::NE => 0,
23            AxisR::E => 1,
24            AxisR::SE => 2,
25        }
26    }
27
28    fn from_index(index: usize) -> Option<Self>
29    where
30        Self: Sized,
31    {
32        Some(match index {
33            0 => AxisR::NE,
34            1 => AxisR::E,
35            2 => AxisR::SE,
36            _ => return None,
37        })
38    }
39
40    unsafe fn from_index_unchecked(index: usize) -> Self {
41        match index {
42            0 => AxisR::NE,
43            1 => AxisR::E,
44            2 => AxisR::SE,
45            _ => unreachable_debug_checked(),
46        }
47    }
48
49    fn foward(self) -> Self::Direction {
50        unsafe { AxisDR::from_index_unchecked(self.to_index()) }
51    }
52
53    fn backward(self) -> Self::Direction {
54        unsafe { AxisDR::from_index_unchecked(self.to_index() + Self::COUNT) }
55    }
56
57    fn from_direction(dir: Self::Direction) -> Self {
58        let i = dir.to_index();
59        unsafe { Self::from_index_unchecked(if i >= Self::COUNT { i - Self::COUNT } else { i }) }
60    }
61
62    fn is_forward_direction(dir: &Self::Direction) -> bool {
63        dir.dir_to_index() < Self::COUNT
64    }
65}
66
67/// Point top Directed Hex Direcion.
68#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
69pub enum AxisDR {
70    NE = 0,
71    E = 1,
72    SE = 2,
73    SW = 3,
74    W = 4,
75    NW = 5,
76}
77
78impl Axis for AxisDR {
79    const COUNT: usize = 6;
80    const DIRECTED: bool = true;
81    type Direction = Self;
82
83    fn to_index(&self) -> usize {
84        match self {
85            AxisDR::NE => 0,
86            AxisDR::E => 1,
87            AxisDR::SE => 2,
88            AxisDR::SW => 3,
89            AxisDR::W => 4,
90            AxisDR::NW => 5,
91        }
92    }
93
94    fn from_index(index: usize) -> Option<Self>
95    where
96        Self: Sized,
97    {
98        Some(match index {
99            0 => AxisDR::NE,
100            1 => AxisDR::E,
101            2 => AxisDR::SE,
102            3 => AxisDR::SW,
103            4 => AxisDR::W,
104            5 => AxisDR::NW,
105            _ => return None,
106        })
107    }
108
109    unsafe fn from_index_unchecked(index: usize) -> Self {
110        match index {
111            0 => AxisDR::NE,
112            1 => AxisDR::E,
113            2 => AxisDR::SE,
114            3 => AxisDR::SW,
115            4 => AxisDR::W,
116            5 => AxisDR::NW,
117            _ => unreachable_debug_checked(),
118        }
119    }
120
121    fn foward(self) -> Self::Direction {
122        self
123    }
124
125    fn backward(self) -> Self::Direction {
126        match self {
127            AxisDR::NE => AxisDR::SW,
128            AxisDR::E => AxisDR::W,
129            AxisDR::SE => AxisDR::NW,
130            AxisDR::SW => AxisDR::NE,
131            AxisDR::W => AxisDR::E,
132            AxisDR::NW => AxisDR::SE,
133        }
134    }
135
136    fn from_direction(dir: Self::Direction) -> Self {
137        dir
138    }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
142/// Flat top Hex Direction.
143pub enum AxisQ {
144    N = 0,
145    NE = 1,
146    SE = 2,
147}
148
149impl Axis for AxisQ {
150    const COUNT: usize = 3;
151    const DIRECTED: bool = false;
152    type Direction = AxisDQ;
153
154    fn to_index(&self) -> usize {
155        match self {
156            AxisQ::N => 0,
157            AxisQ::NE => 1,
158            AxisQ::SE => 2,
159        }
160    }
161
162    fn from_index(index: usize) -> Option<Self>
163    where
164        Self: Sized,
165    {
166        Some(match index {
167            0 => AxisQ::N,
168            1 => AxisQ::NE,
169            2 => AxisQ::SE,
170            _ => return None,
171        })
172    }
173
174    unsafe fn from_index_unchecked(index: usize) -> Self {
175        match index {
176            0 => AxisQ::N,
177            1 => AxisQ::NE,
178            2 => AxisQ::SE,
179            _ => unreachable_debug_checked(),
180        }
181    }
182
183    fn foward(self) -> Self::Direction {
184        unsafe { AxisDQ::from_index_unchecked(self.to_index()) }
185    }
186
187    fn backward(self) -> Self::Direction {
188        unsafe { AxisDQ::from_index_unchecked(self.to_index() + 3) }
189    }
190
191    fn from_direction(dir: Self::Direction) -> Self {
192        let i = dir.dir_to_index();
193        unsafe { Self::from_index_unchecked(if i < Self::COUNT { i } else { i - Self::COUNT }) }
194    }
195
196    fn is_forward_direction(dir: &Self::Direction) -> bool {
197        dir.dir_to_index() < Self::COUNT
198    }
199}
200
201/// Flat top Directed Hex Direction.
202#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
203pub enum AxisDQ {
204    N = 0,
205    NE = 1,
206    SE = 2,
207    S = 3,
208    SW = 4,
209    NW = 5,
210}
211
212impl Axis for AxisDQ {
213    const COUNT: usize = 6;
214    const DIRECTED: bool = true;
215    type Direction = Self;
216
217    fn to_index(&self) -> usize {
218        match self {
219            AxisDQ::N => 0,
220            AxisDQ::NE => 1,
221            AxisDQ::SE => 2,
222            AxisDQ::S => 3,
223            AxisDQ::SW => 4,
224            AxisDQ::NW => 5,
225        }
226    }
227
228    fn from_index(index: usize) -> Option<Self>
229    where
230        Self: Sized,
231    {
232        Some(match index {
233            0 => AxisDQ::N,
234            1 => AxisDQ::NE,
235            2 => AxisDQ::SE,
236            3 => AxisDQ::S,
237            4 => AxisDQ::SW,
238            5 => AxisDQ::NW,
239            _ => return None,
240        })
241    }
242
243    unsafe fn from_index_unchecked(index: usize) -> Self {
244        match index {
245            0 => AxisDQ::N,
246            1 => AxisDQ::NE,
247            2 => AxisDQ::SE,
248            3 => AxisDQ::S,
249            4 => AxisDQ::SW,
250            5 => AxisDQ::NW,
251            _ => unreachable_debug_checked(),
252        }
253    }
254
255    fn foward(self) -> Self::Direction {
256        self
257    }
258
259    fn backward(self) -> Self::Direction {
260        match self {
261            AxisDQ::N => AxisDQ::S,
262            AxisDQ::NE => AxisDQ::SW,
263            AxisDQ::SE => AxisDQ::NW,
264            AxisDQ::S => AxisDQ::N,
265            AxisDQ::SW => AxisDQ::NE,
266            AxisDQ::NW => AxisDQ::SE,
267        }
268    }
269
270    fn from_direction(dir: Self::Direction) -> Self {
271        dir
272    }
273}
274
275/// Whether the offset is even.
276pub trait OE {
277    const IS_EVEN: bool;
278    const CONVERT_OFFSET: usize = if Self::IS_EVEN { 1 } else { 0 };
279}
280/// Whether the hex graph is point top or flat top.
281pub trait RQ {
282    const IS_FLAT_TOP: bool;
283}
284
285/// Point-top + Odd Shape.
286#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
287pub enum OddR {}
288impl OE for OddR {
289    const IS_EVEN: bool = false;
290}
291impl RQ for OddR {
292    const IS_FLAT_TOP: bool = false;
293}
294
295/// Point-top + Even Shape.
296#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
297pub enum EvenR {}
298impl OE for EvenR {
299    const IS_EVEN: bool = true;
300}
301impl RQ for EvenR {
302    const IS_FLAT_TOP: bool = false;
303}
304
305/// Odd-top + Even Shape.
306#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
307pub enum OddQ {}
308impl OE for OddQ {
309    const IS_EVEN: bool = false;
310}
311impl RQ for OddQ {
312    const IS_FLAT_TOP: bool = false;
313}
314
315/// Flat-top + Even Shape.
316#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
317pub enum EvenQ {}
318impl OE for EvenQ {
319    const IS_EVEN: bool = true;
320}
321impl RQ for EvenQ {
322    const IS_FLAT_TOP: bool = false;
323}
324
325/// Marker to show the graph have loop.
326pub trait LoopMarker {}
327/// No loop marker.
328impl LoopMarker for () {}
329
330///Marker for E-W direction Loop.
331#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
332pub enum LoopEW {}
333impl LoopMarker for LoopEW {}
334#[deprecated(note = "Use LoopEW instead.")]
335pub type LEW = LoopEW;
336
337///Marker to tell the graph is directed.
338#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
339pub struct DirectedMarker<T>(PhantomData<fn() -> T>);
340impl<T: OE> OE for DirectedMarker<T> {
341    const IS_EVEN: bool = T::IS_EVEN;
342    const CONVERT_OFFSET: usize = T::CONVERT_OFFSET;
343}
344impl<T: RQ> RQ for DirectedMarker<T> {
345    const IS_FLAT_TOP: bool = T::IS_FLAT_TOP;
346}