Skip to main content

htree/
lib.rs

1
2//! Crate for describing an H Tree fractal
3//!
4//! Provides the HTree struct which can be turned into an iterator over the lines contained within the H Tree.
5//! <https://en.wikipedia.org/wiki/H_tree>
6
7#![feature(int_log)]
8
9use num::Float;
10use std::marker::PhantomData;
11const SCALE_HEIGHT: f64 = 0.7071067811865475244;
12
13
14#[derive(Clone, Copy, Debug)]
15pub struct HTree<T> {
16    order: usize,
17    _marker: PhantomData<T>,
18}
19
20pub struct HTreeIterator<T>
21where
22    T: Float,
23{
24    h_tree: HTree<T>,
25    index: usize,
26}
27
28impl<T> HTree<T>
29where
30    T: Float,
31{
32
33    /// Returns an instance of HTree up to specified order.
34    /// 
35    /// # Examples
36    /// 
37    /// ```
38    /// use htree::HTree;
39    /// let htree:HTree<f32>=HTree::new(10);
40    /// ```
41    pub fn new(order: usize) -> HTree<T> {
42        HTree {
43            order,
44            _marker: PhantomData {},
45        }
46    }
47}
48impl<T> Iterator for HTreeIterator<T>
49where
50    T: Float,
51{
52    type Item = ((T, T), (T, T));
53    fn next(&mut self) -> Option<Self::Item> {
54        self.index += 1;
55        let order_index = self.index.ilog2() as u32;
56        if order_index > self.h_tree.order as u32 {
57            return None;
58        }
59        let iteration_index = self.index as u32 - (1u32 << order_index);
60
61        let num_vertical_rectangles = 1u32 << (order_index + 1) / 2;
62        let num_horizontal_rectangles = 1u32 << order_index / 2 + 1;
63        let num_rectangles = num_vertical_rectangles * num_horizontal_rectangles;
64        assert_eq!(num_rectangles >= iteration_index * 2, true);
65
66        let rectangle_index = 2 * iteration_index;
67        let num_x_start;
68        let num_y_start;
69        let num_x_end;
70        let num_y_end;
71        if order_index % 2 == 1 {
72            // direction ==1 -> vertical
73            //iteration_index=y+height*x
74            num_y_start = rectangle_index % num_vertical_rectangles;
75            num_x_start = (rectangle_index - num_y_start) / num_vertical_rectangles;
76            num_y_end = (rectangle_index + 1) % num_vertical_rectangles;
77            num_x_end = ((rectangle_index + 1) - num_y_end) / num_vertical_rectangles;
78        } else {
79            // direction ==0 -> horizontal
80            //iteration_index=x+width*y
81            num_x_start = rectangle_index % num_horizontal_rectangles;
82            num_y_start = (rectangle_index - num_x_start) / num_horizontal_rectangles;
83            num_x_end = (rectangle_index + 1) % num_horizontal_rectangles;
84            num_y_end = ((rectangle_index + 1) - num_x_end) / num_horizontal_rectangles;
85        }
86
87        let x_start: T = (T::from(num_x_start).unwrap() + T::from(0.5).unwrap())
88            / T::from(num_horizontal_rectangles).unwrap();
89        let x_end: T = (T::from(num_x_end).unwrap() + T::from(0.5).unwrap())
90            / T::from(num_horizontal_rectangles).unwrap();
91        let y_start: T = (T::from(num_y_start).unwrap() + T::from(0.5).unwrap())
92            / T::from(num_vertical_rectangles).unwrap();
93        let y_end: T = (T::from(num_y_end).unwrap() + T::from(0.5).unwrap())
94            / T::from(num_vertical_rectangles).unwrap();
95        Some((
96            (x_start, y_start * T::from(SCALE_HEIGHT).unwrap()),
97            (x_end, y_end * T::from(SCALE_HEIGHT).unwrap()),
98        ))
99    }
100}
101
102impl<T> IntoIterator for HTree<T>
103where
104    T: Float,
105{
106    type Item = ((T, T), (T, T));
107    type IntoIter = HTreeIterator<T>;
108
109
110    /// Returns an HTreeIterator which iterates over lines of the HTree.
111    /// 
112    /// # Examples
113    /// 
114    /// ```
115    /// // coordinates are of type f32
116    /// // HTree iterates up to order 10
117    /// use htree::HTree;
118    /// let htree:HTree<f32>=HTree::new(10);
119    /// for (start,stop) in htree.into_iter(){
120    ///     let (start_x,start_y)=start;
121    ///     let (stop_x,stop_y)=stop;
122    ///     println!("line from (x={start_x},y={start_y}) to x={stop_x},y={stop_y})");
123    /// 
124    /// }
125    /// 
126    /// ```
127    fn into_iter(self) -> Self::IntoIter {
128        HTreeIterator {
129            h_tree: self,
130            index: 0,
131        }
132    }
133}
134
135