|
1 | 1 | use crate::element::Polygon;
|
2 |
| -use crate::style::ShapeStyle; |
| 2 | +use crate::style::{colors::BLUE, Color, ShapeStyle}; |
| 3 | +use std::marker::PhantomData; |
| 4 | +pub trait Direction<X, Y, Z> { |
| 5 | + type Input1Type; |
| 6 | + type Input2Type; |
| 7 | + type OutputType; |
| 8 | + fn make_coord( |
| 9 | + free_vars: (Self::Input1Type, Self::Input2Type), |
| 10 | + result: Self::OutputType, |
| 11 | + ) -> (X, Y, Z); |
| 12 | +} |
| 13 | + |
| 14 | +macro_rules! define_panel_descriptor { |
| 15 | + ($name: ident, $var1: ident, $var2: ident, $out: ident, ($first: ident, $second:ident) -> $result: ident = $output: expr) => { |
| 16 | + pub struct $name; |
| 17 | + impl<X, Y, Z> Direction<X, Y, Z> for $name { |
| 18 | + type Input1Type = $var1; |
| 19 | + type Input2Type = $var2; |
| 20 | + type OutputType = $out; |
| 21 | + fn make_coord( |
| 22 | + ($first, $second): (Self::Input1Type, Self::Input2Type), |
| 23 | + $result: Self::OutputType, |
| 24 | + ) -> (X, Y, Z) { |
| 25 | + $output |
| 26 | + } |
| 27 | + } |
| 28 | + }; |
| 29 | +} |
| 30 | + |
| 31 | +define_panel_descriptor!(XOY, X, Y, Z, (x, y) -> z = (x,y,z)); |
| 32 | +define_panel_descriptor!(XOZ, X, Z, Y, (x, z) -> y = (x,y,z)); |
| 33 | +define_panel_descriptor!(YOZ, Y, Z, X, (y, z) -> x = (x,y,z)); |
| 34 | + |
| 35 | +enum StyleConfig<'a, T> { |
| 36 | + Fixed(ShapeStyle), |
| 37 | + Function(&'a dyn Fn(&T) -> ShapeStyle), |
| 38 | +} |
| 39 | + |
| 40 | +impl<T> StyleConfig<'_, T> { |
| 41 | + fn get_style(&self, v: &T) -> ShapeStyle { |
| 42 | + match self { |
| 43 | + StyleConfig::Fixed(s) => s.clone(), |
| 44 | + StyleConfig::Function(f) => f(v), |
| 45 | + } |
| 46 | + } |
| 47 | +} |
| 48 | + |
3 | 49 | /// The surface series.
|
4 | 50 | ///
|
5 | 51 | /// Currently the surface is representing any surface in form
|
6 | 52 | /// y = f(x,z)
|
7 | 53 | ///
|
8 | 54 | /// TODO: make this more general
|
9 |
| -pub struct SurfaceSeries<X, Y, Z> { |
10 |
| - x_data: Vec<X>, |
11 |
| - y_data: Vec<Y>, |
12 |
| - z_data: Vec<Z>, |
13 |
| - style: ShapeStyle, |
14 |
| - size: usize, |
15 |
| - state: usize, |
| 55 | +pub struct SurfaceSeries<'a, X, Y, Z, D, SurfaceFunc> |
| 56 | +where |
| 57 | + D: Direction<X, Y, Z>, |
| 58 | + SurfaceFunc: Fn(D::Input1Type, D::Input2Type) -> D::OutputType, |
| 59 | +{ |
| 60 | + free_var_1: Vec<D::Input1Type>, |
| 61 | + free_var_2: Vec<D::Input2Type>, |
| 62 | + surface_f: SurfaceFunc, |
| 63 | + style: StyleConfig<'a, D::OutputType>, |
| 64 | + adv: bool, |
| 65 | + vidx_1: usize, |
| 66 | + vidx_2: usize, |
| 67 | + _phantom: PhantomData<(X, Y, Z, D)>, |
16 | 68 | }
|
17 | 69 |
|
18 |
| -impl<X, Y, Z> SurfaceSeries<X, Y, Z> { |
19 |
| - pub fn new<XS, ZS, YF, S>(xs: XS, zs: ZS, y_func: YF, style: S) -> Self |
20 |
| - where |
21 |
| - YF: Fn(&X, &Z) -> Y, |
22 |
| - XS: Iterator<Item = X>, |
23 |
| - ZS: Iterator<Item = Z>, |
24 |
| - S: Into<ShapeStyle>, |
25 |
| - { |
26 |
| - let x_data: Vec<_> = xs.collect(); |
27 |
| - let z_data: Vec<_> = zs.collect(); |
28 |
| - let y_data: Vec<_> = x_data |
29 |
| - .iter() |
30 |
| - .map(|x| z_data.iter().map(move |z| (x, z))) |
31 |
| - .flatten() |
32 |
| - .map(|(x, z)| y_func(x, z)) |
33 |
| - .collect(); |
34 |
| - let size = (x_data.len().max(1) - 1) * (z_data.len().max(1) - 1); |
| 70 | +impl<'a, X, Y, Z, D, SurfaceFunc> SurfaceSeries<'a, X, Y, Z, D, SurfaceFunc> |
| 71 | +where |
| 72 | + D: Direction<X, Y, Z>, |
| 73 | + SurfaceFunc: Fn(D::Input1Type, D::Input2Type) -> D::OutputType, |
| 74 | +{ |
| 75 | + pub fn new<IterA: Iterator<Item = D::Input1Type>, IterB: Iterator<Item = D::Input2Type>>( |
| 76 | + first_iter: IterA, |
| 77 | + second_iter: IterB, |
| 78 | + func: SurfaceFunc, |
| 79 | + ) -> Self { |
35 | 80 | Self {
|
36 |
| - x_data, |
37 |
| - y_data, |
38 |
| - z_data, |
39 |
| - style: style.into(), |
40 |
| - size, |
41 |
| - state: 0, |
| 81 | + free_var_1: first_iter.collect(), |
| 82 | + free_var_2: second_iter.collect(), |
| 83 | + surface_f: func, |
| 84 | + style: StyleConfig::Fixed(BLUE.mix(0.4).filled()), |
| 85 | + adv: true, |
| 86 | + vidx_1: 0, |
| 87 | + vidx_2: 0, |
| 88 | + _phantom: PhantomData, |
42 | 89 | }
|
43 | 90 | }
|
44 | 91 |
|
45 |
| - fn point_at(&self, x: usize, z: usize) -> (X, Y, Z) |
| 92 | + pub fn style_func<F: Fn(&D::OutputType) -> ShapeStyle>(mut self, f: &'a F) -> Self { |
| 93 | + self.style = StyleConfig::Function(f); |
| 94 | + self |
| 95 | + } |
| 96 | + |
| 97 | + pub fn style<S: Into<ShapeStyle>>(mut self, s: S) -> Self { |
| 98 | + self.style = StyleConfig::Fixed(s.into()); |
| 99 | + self |
| 100 | + } |
| 101 | + |
| 102 | + fn get_next_free_value_2(&mut self) -> Option<[D::Input2Type; 2]> |
46 | 103 | where
|
47 |
| - X: Clone, |
48 |
| - Y: Clone, |
49 |
| - Z: Clone, |
| 104 | + D::Input2Type: Clone, |
50 | 105 | {
|
51 |
| - ( |
52 |
| - self.x_data[x].clone(), |
53 |
| - self.y_data[x * self.z_data.len() + z].clone(), |
54 |
| - self.z_data[z].clone(), |
55 |
| - ) |
| 106 | + if self.adv { |
| 107 | + if self.vidx_2 + 1 < self.free_var_2.len() { |
| 108 | + self.vidx_2 += 1; |
| 109 | + return Some([ |
| 110 | + self.free_var_2[self.vidx_2 - 1].clone(), |
| 111 | + self.free_var_2[self.vidx_2].clone(), |
| 112 | + ]); |
| 113 | + } |
| 114 | + self.vidx_2 += 1; |
| 115 | + } else { |
| 116 | + if self.vidx_2 > 1 { |
| 117 | + self.vidx_2 -= 1; |
| 118 | + return Some([ |
| 119 | + self.free_var_2[self.vidx_2 - 1].clone(), |
| 120 | + self.free_var_2[self.vidx_2].clone(), |
| 121 | + ]); |
| 122 | + } |
| 123 | + self.vidx_2 = self.vidx_2.max(1) - 1; |
| 124 | + } |
| 125 | + None |
56 | 126 | }
|
57 | 127 | }
|
58 | 128 |
|
59 |
| -impl<X: Clone, Y: Clone, Z: Clone> Iterator for SurfaceSeries<X, Y, Z> { |
60 |
| - type Item = Polygon<(X, Y, Z)>; |
61 |
| - |
62 |
| - fn next(&mut self) -> Option<Self::Item> { |
63 |
| - if self.size <= self.state { |
64 |
| - return None; |
| 129 | +macro_rules! impl_constructor { |
| 130 | + ($dir: ty, $name: ident) => { |
| 131 | + impl<'a, X, Y, Z, SurfaceFunc> SurfaceSeries<'a, X, Y, Z, $dir, SurfaceFunc> |
| 132 | + where |
| 133 | + SurfaceFunc: Fn( |
| 134 | + <$dir as Direction<X, Y, Z>>::Input1Type, |
| 135 | + <$dir as Direction<X, Y, Z>>::Input2Type, |
| 136 | + ) -> <$dir as Direction<X, Y, Z>>::OutputType, |
| 137 | + { |
| 138 | + pub fn $name<IterA, IterB>(a: IterA, b: IterB, f: SurfaceFunc) -> Self |
| 139 | + where |
| 140 | + IterA: DoubleEndedIterator<Item = <$dir as Direction<X, Y, Z>>::Input1Type>, |
| 141 | + IterB: DoubleEndedIterator<Item = <$dir as Direction<X, Y, Z>>::Input2Type>, |
| 142 | + { |
| 143 | + Self::new(a, b, f) |
| 144 | + } |
65 | 145 | }
|
| 146 | + }; |
| 147 | +} |
66 | 148 |
|
67 |
| - let x = self.state / (self.z_data.len() - 1); |
68 |
| - let z = self.state % (self.z_data.len() - 1); |
69 |
| - |
70 |
| - self.state += 1; |
| 149 | +impl_constructor!(XOY, xoy); |
| 150 | +impl_constructor!(XOZ, xoz); |
| 151 | +impl_constructor!(YOZ, yoz); |
| 152 | +impl<'a, X, Y, Z, D, SurfaceFunc> Iterator for SurfaceSeries<'a, X, Y, Z, D, SurfaceFunc> |
| 153 | +where |
| 154 | + D: Direction<X, Y, Z>, |
| 155 | + D::Input1Type: Clone, |
| 156 | + D::Input2Type: Clone, |
| 157 | + SurfaceFunc: Fn(D::Input1Type, D::Input2Type) -> D::OutputType, |
| 158 | +{ |
| 159 | + type Item = Polygon<(X, Y, Z)>; |
| 160 | + fn next(&mut self) -> Option<Self::Item> { |
| 161 | + let (b0, b1) = if let Some([b0, b1]) = self.get_next_free_value_2() { |
| 162 | + (b0, b1) |
| 163 | + } else { |
| 164 | + self.vidx_1 += 1; |
| 165 | + self.adv = !self.adv; |
| 166 | + if let Some([b0, b1]) = self.get_next_free_value_2() { |
| 167 | + (b0, b1) |
| 168 | + } else { |
| 169 | + return None; |
| 170 | + } |
| 171 | + }; |
71 | 172 |
|
72 |
| - Some(Polygon::new( |
73 |
| - vec![ |
74 |
| - self.point_at(x, z), |
75 |
| - self.point_at(x, z + 1), |
76 |
| - self.point_at(x + 1, z + 1), |
77 |
| - self.point_at(x + 1, z), |
78 |
| - ], |
79 |
| - self.style.clone(), |
80 |
| - )) |
| 173 | + match ( |
| 174 | + self.free_var_1.get(self.vidx_1), |
| 175 | + self.free_var_1.get(self.vidx_1 + 1), |
| 176 | + ) { |
| 177 | + (Some(a0), Some(a1)) => { |
| 178 | + let value = (self.surface_f)(a0.clone(), b0.clone()); |
| 179 | + let style = self.style.get_style(&value); |
| 180 | + let vert = vec![ |
| 181 | + D::make_coord((a0.clone(), b0.clone()), value), |
| 182 | + D::make_coord( |
| 183 | + (a0.clone(), b1.clone()), |
| 184 | + (self.surface_f)(a0.clone(), b1.clone()), |
| 185 | + ), |
| 186 | + D::make_coord( |
| 187 | + (a1.clone(), b1.clone()), |
| 188 | + (self.surface_f)(a1.clone(), b1.clone()), |
| 189 | + ), |
| 190 | + D::make_coord( |
| 191 | + (a1.clone(), b0.clone()), |
| 192 | + (self.surface_f)(a1.clone(), b0.clone()), |
| 193 | + ), |
| 194 | + ]; |
| 195 | + return Some(Polygon::new(vert, style)); |
| 196 | + } |
| 197 | + _ => { |
| 198 | + return None; |
| 199 | + } |
| 200 | + } |
81 | 201 | }
|
82 | 202 | }
|
0 commit comments