tg_geom/
index.rs

1//! Spatial indexing.
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
4#[repr(u32)]
5pub enum IndexKind {
6    #[default]
7    Default = 0,
8    None = 1,
9    Natural = 2,
10    YStripes = 3,
11}
12
13impl From<tg_geom_sys::tg_index> for IndexKind {
14    fn from(ix: tg_geom_sys::tg_index) -> Self {
15        match ix {
16            tg_geom_sys::tg_index_TG_DEFAULT => IndexKind::Default,
17            tg_geom_sys::tg_index_TG_NONE => IndexKind::None,
18            tg_geom_sys::tg_index_TG_NATURAL => IndexKind::Natural,
19            tg_geom_sys::tg_index_TG_YSTRIPES => IndexKind::YStripes,
20            _ => unreachable!("unknown index kind: {ix}"),
21        }
22    }
23}
24
25impl From<IndexKind> for tg_geom_sys::tg_index {
26    fn from(ix: IndexKind) -> Self {
27        match ix {
28            IndexKind::Default => tg_geom_sys::tg_index_TG_DEFAULT,
29            IndexKind::None => tg_geom_sys::tg_index_TG_NONE,
30            IndexKind::Natural => tg_geom_sys::tg_index_TG_NATURAL,
31            IndexKind::YStripes => tg_geom_sys::tg_index_TG_YSTRIPES,
32        }
33    }
34}
35
36pub fn set_default_index(ix: IndexKind) {
37    unsafe { tg_geom_sys::tg_env_set_index(ix.into()) }
38}
39
40pub fn set_default_index_spread(spread: i32) {
41    unsafe { tg_geom_sys::tg_env_set_index_spread(spread) }
42}
43
44pub fn set_print_fixed_floats(print: bool) {
45    unsafe { tg_geom_sys::tg_env_set_print_fixed_floats(print) }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use crate::{Point, Ring};
52
53    fn p(x: f64, y: f64) -> Point {
54        Point::new(x, y)
55    }
56
57    fn octagon() -> Vec<Point> {
58        vec![
59            p(3.0, 0.0),
60            p(7.0, 0.0),
61            p(10.0, 3.0),
62            p(10.0, 7.0),
63            p(7.0, 10.0),
64            p(3.0, 10.0),
65            p(0.0, 7.0),
66            p(0.0, 3.0),
67            p(3.0, 0.0),
68        ]
69    }
70
71    #[test]
72    fn test_index_kind_variants() {
73        assert_eq!(IndexKind::Default as u32, 0);
74        assert_eq!(IndexKind::None as u32, 1);
75        assert_eq!(IndexKind::Natural as u32, 2);
76        assert_eq!(IndexKind::YStripes as u32, 3);
77    }
78
79    #[test]
80    fn test_index_kind_default() {
81        let ix: IndexKind = Default::default();
82        assert_eq!(ix, IndexKind::Default);
83    }
84
85    #[test]
86    fn test_index_kind_copy() {
87        let ix1 = IndexKind::Natural;
88        let ix2 = ix1;
89        assert_eq!(ix1, ix2);
90    }
91
92    #[test]
93    fn test_index_kind_eq() {
94        assert_eq!(IndexKind::None, IndexKind::None);
95        assert_ne!(IndexKind::None, IndexKind::Natural);
96    }
97
98    #[test]
99    fn test_index_kind_debug() {
100        let debug_str = format!("{:?}", IndexKind::Natural);
101        assert!(debug_str.contains("Natural"));
102    }
103
104    #[test]
105    fn test_index_kind_sys_roundtrip() {
106        let kinds = [
107            IndexKind::Default,
108            IndexKind::None,
109            IndexKind::Natural,
110            IndexKind::YStripes,
111        ];
112        for kind in &kinds {
113            let sys_kind: tg_geom_sys::tg_index = (*kind).into();
114            let back: IndexKind = sys_kind.into();
115            assert_eq!(*kind, back);
116        }
117    }
118
119    #[test]
120    fn test_set_default_index() {
121        set_default_index(IndexKind::Natural);
122        set_default_index(IndexKind::None);
123        set_default_index(IndexKind::YStripes);
124        set_default_index(IndexKind::Default);
125    }
126
127    #[test]
128    fn test_set_default_index_spread() {
129        set_default_index_spread(4);
130        set_default_index_spread(8);
131        set_default_index_spread(16);
132    }
133
134    #[test]
135    fn test_set_print_fixed_floats() {
136        set_print_fixed_floats(true);
137        set_print_fixed_floats(false);
138    }
139
140    #[test]
141    fn test_ring_index_kinds() {
142        let points = octagon();
143
144        let ring_default = Ring::new(&points).unwrap();
145        let ring_none = Ring::new_ix(&points, IndexKind::None).unwrap();
146        let ring_natural = Ring::new_ix(&points, IndexKind::Natural).unwrap();
147        let ring_ystripes = Ring::new_ix(&points, IndexKind::YStripes).unwrap();
148
149        assert_eq!(ring_default.num_points(), ring_none.num_points());
150        assert_eq!(ring_default.num_points(), ring_natural.num_points());
151        assert_eq!(ring_default.num_points(), ring_ystripes.num_points());
152
153        assert_eq!(ring_default.area(), ring_none.area());
154        assert_eq!(ring_default.area(), ring_natural.area());
155        assert_eq!(ring_default.area(), ring_ystripes.area());
156    }
157
158    #[test]
159    fn test_ring_index_properties() {
160        let ring_natural = Ring::new_ix(&octagon(), IndexKind::Natural).unwrap();
161
162        let spread = ring_natural.index_spread();
163        let num_levels = ring_natural.index_num_levels();
164
165        assert!(spread >= 0);
166        assert!(num_levels >= 0);
167
168        if num_levels > 0 {
169            let level0_rects = ring_natural.index_level_num_rects(0);
170            assert!(level0_rects >= 0);
171        }
172    }
173
174    #[test]
175    fn test_ring_none_index() {
176        let ring_none = Ring::new_ix(&octagon(), IndexKind::None).unwrap();
177        assert_eq!(ring_none.index_num_levels(), 0);
178    }
179}