From 30f6c206f75c1baa11e942595a55b5d573543a0c Mon Sep 17 00:00:00 2001 From: sleptworld Date: Sat, 12 Aug 2023 00:36:23 +0800 Subject: [PATCH] DParser Finished, should do more optimimzations --- down.py | 197 +++++++++++++++ src/data/mapper.rs | 8 +- src/data/mod.rs | 466 ++++++++++++++++++++++------------- src/main.rs | 18 +- src/monitor/mod.rs | 16 +- src/render/foreground/imp.rs | 1 + src/render/foreground/mod.rs | 99 +++++++- src/render/imp.rs | 15 +- src/render/mod.rs | 22 +- src/tree.rs | 4 +- 10 files changed, 643 insertions(+), 203 deletions(-) create mode 100644 down.py diff --git a/down.py b/down.py new file mode 100644 index 0000000..648049e --- /dev/null +++ b/down.py @@ -0,0 +1,197 @@ +def _downsample_2d(src, mask, use_mask, method, fill_value, mode_rank, out): + src_w = src.shape[-1] + src_h = src.shape[-2] + out_w = out.shape[-1] + out_h = out.shape[-2] + + if src_w == out_w and src_h == out_h: + return src + + if out_w > src_w or out_h > src_h: + raise ValueError("invalid target size") + + scale_x = src_w / out_w + scale_y = src_h / out_h + + if method == DS_FIRST or method == DS_LAST: + for out_y in range(out_h): + src_yf0 = scale_y * out_y + src_yf1 = src_yf0 + scale_y + src_y0 = int(src_yf0) + src_y1 = int(src_yf1) + if src_y1 == src_yf1 and src_y1 > src_y0: + src_y1 -= 1 + for out_x in range(out_w): + src_xf0 = scale_x * out_x + src_xf1 = src_xf0 + scale_x + src_x0 = int(src_xf0) + src_x1 = int(src_xf1) + if src_x1 == src_xf1 and src_x1 > src_x0: + src_x1 -= 1 + done = False + value = fill_value + for src_y in range(src_y0, src_y1 + 1): + for src_x in range(src_x0, src_x1 + 1): + v = src[src_y, src_x] + if np.isfinite(v) and not (use_mask and mask[src_y, src_x]): + value = v + if method == DS_FIRST: + done = True + break + if done: + break + out[out_y, out_x] = value + + elif method == DS_MODE: + max_value_count = int(scale_x + 1) * int(scale_y + 1) + values = np.zeros((max_value_count,), dtype=src.dtype) + frequencies = np.zeros((max_value_count,), dtype=np.uint32) + for out_y in range(out_h): + src_yf0 = scale_y * out_y + src_yf1 = src_yf0 + scale_y + src_y0 = int(src_yf0) + src_y1 = int(src_yf1) + wy0 = 1.0 - (src_yf0 - src_y0) + wy1 = src_yf1 - src_y1 + if wy1 < _EPS: + wy1 = 1.0 + if src_y1 > src_y0: + src_y1 -= 1 + for out_x in range(out_w): + src_xf0 = scale_x * out_x + src_xf1 = src_xf0 + scale_x + src_x0 = int(src_xf0) + src_x1 = int(src_xf1) + wx0 = 1.0 - (src_xf0 - src_x0) + wx1 = src_xf1 - src_x1 + if wx1 < _EPS: + wx1 = 1.0 + if src_x1 > src_x0: + src_x1 -= 1 + value_count = 0 + for src_y in range(src_y0, src_y1 + 1): + wy = wy0 if (src_y == src_y0) else wy1 if (src_y == src_y1) else 1.0 + for src_x in range(src_x0, src_x1 + 1): + wx = wx0 if (src_x == src_x0) else wx1 if (src_x == src_x1) else 1.0 + v = src[src_y, src_x] + if np.isfinite(v) and not (use_mask and mask[src_y, src_x]): + w = wx * wy + found = False + for i in range(value_count): + if v == values[i]: + frequencies[i] += w + found = True + break + if not found: + values[value_count] = v + frequencies[value_count] = w + value_count += 1 + w_max = -1. + value = fill_value + if mode_rank == 1: + for i in range(value_count): + w = frequencies[i] + if w > w_max: + w_max = w + value = values[i] + elif mode_rank <= max_value_count: + max_frequencies = np.full(mode_rank, -1.0, dtype=np.float64) + indices = np.zeros(mode_rank, dtype=np.int64) + for i in range(value_count): + w = frequencies[i] + for j in range(mode_rank): + if w > max_frequencies[j]: + max_frequencies[j] = w + indices[j] = i + break + value = values[indices[mode_rank - 1]] + + out[out_y, out_x] = value + + elif method == DS_MEAN: + for out_y in range(out_h): + src_yf0 = scale_y * out_y + src_yf1 = src_yf0 + scale_y + src_y0 = int(src_yf0) + src_y1 = int(src_yf1) + wy0 = 1.0 - (src_yf0 - src_y0) + wy1 = src_yf1 - src_y1 + if wy1 < _EPS: + wy1 = 1.0 + if src_y1 > src_y0: + src_y1 -= 1 + for out_x in range(out_w): + src_xf0 = scale_x * out_x + src_xf1 = src_xf0 + scale_x + src_x0 = int(src_xf0) + src_x1 = int(src_xf1) + wx0 = 1.0 - (src_xf0 - src_x0) + wx1 = src_xf1 - src_x1 + if wx1 < _EPS: + wx1 = 1.0 + if src_x1 > src_x0: + src_x1 -= 1 + v_sum = 0.0 + w_sum = 0.0 + for src_y in range(src_y0, src_y1 + 1): + wy = wy0 if (src_y == src_y0) else wy1 if (src_y == src_y1) else 1.0 + for src_x in range(src_x0, src_x1 + 1): + wx = wx0 if (src_x == src_x0) else wx1 if (src_x == src_x1) else 1.0 + v = src[src_y, src_x] + if np.isfinite(v) and not (use_mask and mask[src_y, src_x]): + w = wx * wy + v_sum += w * v + w_sum += w + if w_sum < _EPS: + out[out_y, out_x] = fill_value + else: + out[out_y, out_x] = v_sum / w_sum + + elif method == DS_VAR or method == DS_STD: + for out_y in range(out_h): + src_yf0 = scale_y * out_y + src_yf1 = src_yf0 + scale_y + src_y0 = int(src_yf0) + src_y1 = int(src_yf1) + wy0 = 1.0 - (src_yf0 - src_y0) + wy1 = src_yf1 - src_y1 + if wy1 < _EPS: + wy1 = 1.0 + if src_y1 > src_y0: + src_y1 -= 1 + for out_x in range(out_w): + src_xf0 = scale_x * out_x + src_xf1 = src_xf0 + scale_x + src_x0 = int(src_xf0) + src_x1 = int(src_xf1) + wx0 = 1.0 - (src_xf0 - src_x0) + wx1 = src_xf1 - src_x1 + if wx1 < _EPS: + wx1 = 1.0 + if src_x1 > src_x0: + src_x1 -= 1 + v_sum = 0.0 + w_sum = 0.0 + wv_sum = 0.0 + wvv_sum = 0.0 + for src_y in range(src_y0, src_y1 + 1): + wy = wy0 if (src_y == src_y0) else wy1 if (src_y == src_y1) else 1.0 + for src_x in range(src_x0, src_x1 + 1): + wx = wx0 if (src_x == src_x0) else wx1 if (src_x == src_x1) else 1.0 + v = src[src_y, src_x] + if np.isfinite(v) and not (use_mask and mask[src_y, src_x]): + w = wx * wy + v_sum += v + w_sum += w + wv_sum += w * v + wvv_sum += w * v * v + if w_sum < _EPS: + out[out_y, out_x] = fill_value + else: + out[out_y, out_x] = (wvv_sum * w_sum - wv_sum * wv_sum) / w_sum / w_sum + if method == DS_STD: + out = np.sqrt(out).astype(out.dtype) + else: + raise ValueError('invalid upsampling method') + + return out \ No newline at end of file diff --git a/src/data/mapper.rs b/src/data/mapper.rs index 3d6bc88..28af08d 100644 --- a/src/data/mapper.rs +++ b/src/data/mapper.rs @@ -13,6 +13,7 @@ pub struct Mapper { range: (Range, Range), bounds: (f64, f64, f64, f64), } +unsafe impl Sync for Mapper {} impl From for Mapper { fn from(proj: Proj) -> Self { @@ -77,15 +78,15 @@ impl Mapper { pub fn ring_map(&self, ring: &LineString) -> Result { let mut result = Vec::new(); for l in ring.lines() { - let start_projected = self.map((l.start.x, l.start.y))?; - let end_projected = self.map((l.end.x, l.end.y))?; - + let start_projected: (f64, f64) = l.start.into(); + let end_projected: (f64, f64) = l.end.into(); let cartesian_start = self.cartesian(l.start.x, l.start.y); let cartesian_end = self.cartesian(l.end.x, l.end.y); let delta2 = 0.5; let depth = 16; let mut res: Vec = Vec::new(); + res.push(l.start); self.resample_line_to( start_projected, end_projected, @@ -98,6 +99,7 @@ impl Mapper { depth, &mut res, )?; + res.push(l.end); result.extend(res); } diff --git a/src/data/mod.rs b/src/data/mod.rs index 7409f0a..ef393b8 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,5 +1,5 @@ use ndarray::{ - s, Array, Array1, Array2, Array3, ArrayBase, Ix1, Ix2, OwnedRepr, RawDataClone, ViewRepr, + s, Array, Array1, Array2, Array3, ArrayBase, Axis, Ix1, Ix2, OwnedRepr, RawDataClone, ViewRepr, }; use npyz::{npz::NpzArchive, Deserialize}; use num_traits::{AsPrimitive, FromPrimitive, Num}; @@ -21,11 +21,10 @@ pub enum DataError { }, } -#[derive(PartialEq)] -pub enum Axis { - Asix0, - Axis1, - Axis2, +pub enum DownSampleMeth { + STD, + MEAN, + VAR, } #[derive(Clone, Copy)] @@ -48,6 +47,16 @@ where pub coord_type: CoordType, } +pub type Radar2d = RadarData2d>; + +impl Radar2d { + pub fn load(path: impl AsRef, meth: impl DataLoader) -> Result { + Ok(meth.load(path)?) + } +} + +pub type Radar2dRef<'a, T> = RadarData2d>; + pub struct RadarData3d where T: Num, @@ -68,58 +77,134 @@ where T: Num + AsPrimitive + FromPrimitive + Clone + Debug + PartialOrd + PartialEq, Raw: ndarray::Data + Clone + ndarray::RawDataClone, { - fn value_to_owned(self) -> RadarData2d> { - RadarData2d { - dim1: self.dim1, - dim2: self.dim2, - data: self.data.to_owned(), - coord_type: self.coord_type, + pub fn downsample(&self, output_shape: (usize, usize), meth: DownSampleMeth) -> Radar2d { + let shape = self.data.shape(); + assert!(shape[0] > output_shape.0 && shape[1] > output_shape.1); + + if shape[0] == output_shape.0 && shape[1] == output_shape.1 { + return Radar2d { + dim1: self.dim1.to_owned(), + dim2: self.dim2.to_owned(), + data: self.data.to_owned(), + coord_type: self.coord_type.clone(), + }; } + + let scale_x = shape[1] as f64 / output_shape.1 as f64; + let scale_y = shape[0] as f64 / output_shape.0 as f64; + + let mut output: Array2 = Array2::zeros(output_shape); + + let mut dim1 = Array1::zeros(output_shape.1); + let mut dim2 = Array1::zeros(output_shape.0); + + output.iter_mut().enumerate().for_each(|(s, vv)| { + let ri = s / output_shape.1; + let ci = s % output_shape.1; + let src_yf0 = scale_y * ci as f64; + let src_yf1 = src_yf0 + scale_y; + let src_y0 = src_yf0.floor() as usize; + let src_y1 = src_yf1.floor() as usize; + let src_xf0 = scale_x * ri as f64; + let src_xf1 = src_xf0 + scale_x; + let src_x0 = src_xf0.floor() as usize; + let src_x1 = src_xf1.floor() as usize; + + match meth { + DownSampleMeth::MEAN => {} + DownSampleMeth::VAR | DownSampleMeth::STD => self.var( + src_yf0, src_yf1, src_xf0, src_xf1, src_y0, src_y1, src_x0, src_x1, vv, + ), + } + + dim1[ci] = self.dim1[src_x0]; + dim2[ri] = self.dim2[src_y0]; + }); + + if let DownSampleMeth::STD = meth { + output = output.mapv(|x| T::from_f64(f64::sqrt(x.as_())).unwrap()); + } + + return Radar2d { + dim1, + dim2, + data: output, + coord_type: self.coord_type.clone(), + }; } - fn resample( + fn var( &self, - width_rate: f64, - height_rate: f64, - filter_len: f64, - ) -> Result>, DataError> { - let width_rate = width_rate.min(1.0); - let height_rate = height_rate.min(1.0); - match self.coord_type { - CoordType::Polar => Err(DataError::FormatError), - CoordType::LatLon => { - let width_filtered: ArrayBase, Ix2> = - Self::_resample(&self.data, width_rate, filter_len); + src_yf0: f64, + src_yf1: f64, + src_xf0: f64, + src_xf1: f64, + src_y0: usize, + mut src_y1: usize, + src_x0: usize, + mut src_x1: usize, + row: &mut T, + ) { + let wy0 = 1f64 - (src_yf0 - src_y0 as f64); + let mut wy1 = src_yf1 - src_y1 as f64; + let wx0 = 1f64 - (src_xf0 - src_x0 as f64); + let mut wx1 = src_xf1 - src_x1 as f64; - let result: ArrayBase, Ix2> = - Self::_resample(&width_filtered.t(), height_rate, filter_len) - .t() - .to_owned(); - - let new_dim1: ArrayBase, Ix1> = Self::_resample( - &Array2::from_shape_vec((1, self.dim1.len()), self.dim1.to_vec()).unwrap(), - width_rate, - filter_len, - ) - .slice(s![0, ..]) - .to_owned(); - - let new_dim2: ArrayBase, Ix1> = Self::_resample( - &Array2::from_shape_vec((1, self.dim2.len()), self.dim2.to_vec()).unwrap(), - height_rate, - filter_len, - ) - .slice(s![0, ..]) - .to_owned(); - - Ok(RadarData2d { - dim1: new_dim1, - dim2: new_dim2, - data: result, - coord_type: self.coord_type.to_owned(), - }) + if wy1 < f64::EPSILON { + wy1 = 1f64; + if src_y1 > src_y0 { + src_y1 -= 1; } } + + if wx1 < f64::EPSILON { + wx1 = 1f64; + if src_x1 > src_x0 { + src_x1 -= 1; + } + } + + let mut v_sum: f64 = 0.0; + let mut w_sum = 0f64; + let mut wv_sum = 0f64; + let mut wvv_sum = 0f64; + + for src_y in src_y0..=src_y1 { + let wy = if src_y == src_y0 { + wy0 + } else { + if src_y == src_y1 { + wy1 + } else { + 1.0 + } + }; + for src_x in src_x0..=src_x1 { + let wx = if src_x == src_x0 { + wx0 + } else { + if src_x == src_x1 { + wx1 + } else { + 1.0 + } + }; + + let v = self.data[[src_y, src_x]].as_(); + let w = wx * wy; + + v_sum += v; + w_sum += w; + wv_sum += w * v; + wvv_sum += w * v * v; + } + + if w_sum < f64::EPSILON { + return; + } + + *row = T::from_f64((wvv_sum * w_sum - wv_sum * wv_sum) / w_sum / w_sum).unwrap(); + } } fn split(&self) -> [RadarData2d>; 4] { @@ -158,121 +243,6 @@ where }, ]; } - - fn _resample<'a, V, R: ndarray::Data>( - data: &'a ArrayBase, - rate: f64, - filter_len: f64, - ) -> Array2 - where - V: Num + Clone + AsPrimitive + FromPrimitive, - { - let ori_width = data.ncols(); - let ori_height = data.nrows(); - - let new_width = (ori_width as f64 * rate).ceil() as usize; - let mut result: Array2 = Array2::zeros((ori_height, new_width)); - (0..ori_height).into_iter().for_each(|height| { - for width in 0..new_width { - let center_x = (width as f64 + 0.5) / new_width as f64 * ori_width as f64; - let filter_start = center_x - filter_len / 2.0; - let start_idx = (filter_start - 0.5).ceil() as usize; - - let mut value_sum = 0.0; - let mut filter_sum = 0.0; - - for i in 0..filter_len as usize { - let input_x = start_idx + i; - let weight = windowed_sinc( - (input_x as f64 + 0.5 - center_x) * rate, - (input_x as f64 + 0.5 - filter_start) / filter_len, - ); - value_sum += weight * data[[height, input_x.clamp(0, ori_width - 1)]].as_(); - filter_sum += weight; - } - - result[[height, width]] = V::from_f64(value_sum / filter_sum).unwrap(); - } - }); - result - } -} - -#[inline] -fn windowed_sinc(x: f64, y: f64) -> f64 { - let x = x * PI; - let sinc = if x != 0.0 { f64::sin(x) / x } else { 1.0 }; - let window = if 0f64 <= y && y <= 1.0 { - 1.0 - (y - 0.5).abs() * 2.0 - } else { - 0f64 - }; - sinc * window -} - -pub struct LevelData( - pub Quadtree>>, -); - -impl LevelData -where - T: Num + Clone + AsPrimitive + FromPrimitive + Debug + PartialEq + PartialOrd, -{ - fn value( - level_data: Vec>>, - level_num: usize, - ) -> Vec>> { - if level_num == 0 { - return level_data; - } - - let mut result: Vec>> = - Vec::with_capacity(level_data.len() * 4); - - let results = level_data - .iter() - .flat_map(|v| v.split().into_iter().map(|x| x.value_to_owned())); - - result.extend(results); - - return Self::value(result, level_num - 1); - } - - fn new(data: &RadarData2d>, level: usize, rate: f64) -> Self { - // let rate = 1.0 / level as f64; - let resampled = data.resample(rate, rate, 2.0).unwrap(); - let blocks = Self::value(vec![resampled], level); - let mut tree: Quadtree>> = - quadtree_rs::Quadtree::new(level); - - blocks.into_iter().for_each(|block| { - tree.insert( - AreaBuilder::default() - .anchor(quadtree_rs::point::Point { - x: *block.dim1.first().unwrap() as i64, - y: *block.dim2.first().unwrap() as i64, - }) - .dimensions((block.dim1.len() as i64, block.dim2.len() as i64)) - .build() - .unwrap(), - block, - ); - }); - - Self(tree) - } -} - -pub fn levels(data: Radar2d, levels: usize) -> Vec> -where - T: Num + Clone + AsPrimitive + FromPrimitive + Debug, - T: PartialEq + PartialOrd, -{ - let numerator = 1.0 / levels as f64; - (0..levels) - .into_iter() - .map(|level| LevelData::new(&data, level + 1, 1.0 - level as f64 * numerator)) - .collect() } impl MultiDimensionData for RadarData2d @@ -340,12 +310,162 @@ where } } -pub type Radar2d = RadarData2d>; +// fn resample( +// &self, +// width_rate: f64, +// height_rate: f64, +// filter_len: f64, +// ) -> Result>, DataError> { +// let width_rate = width_rate.min(1.0); +// let height_rate = height_rate.min(1.0); +// match self.coord_type { +// CoordType::Polar => Err(DataError::FormatError), +// CoordType::LatLon => { +// let width_filtered: ArrayBase, Ix2> = +// Self::_resample(&self.data, width_rate, filter_len); -impl Radar2d { - pub fn load(path: impl AsRef, meth: impl DataLoader) -> Result { - Ok(meth.load(path)?) - } +// let result: ArrayBase, Ix2> = +// Self::_resample(&width_filtered.t(), height_rate, filter_len) +// .t() +// .to_owned(); + +// let new_dim1: ArrayBase, Ix1> = Self::_resample( +// &Array2::from_shape_vec((1, self.dim1.len()), self.dim1.to_vec()).unwrap(), +// width_rate, +// filter_len, +// ) +// .slice(s![0, ..]) +// .to_owned(); + +// let new_dim2: ArrayBase, Ix1> = Self::_resample( +// &Array2::from_shape_vec((1, self.dim2.len()), self.dim2.to_vec()).unwrap(), +// height_rate, +// filter_len, +// ) +// .slice(s![0, ..]) +// .to_owned(); + +// Ok(RadarData2d { +// dim1: new_dim1, +// dim2: new_dim2, +// data: result, +// coord_type: self.coord_type.to_owned(), +// }) +// } +// } +// } + +// fn _resample<'a, V, R: ndarray::Data>( +// data: &'a ArrayBase, +// rate: f64, +// filter_len: f64, +// ) -> Array2 +// where +// V: Num + Clone + AsPrimitive + FromPrimitive, +// { +// let ori_width = data.ncols(); +// let ori_height = data.nrows(); + +// let new_width = (ori_width as f64 * rate).ceil() as usize; +// let mut result: Array2 = Array2::zeros((ori_height, new_width)); +// (0..ori_height).into_iter().for_each(|height| { +// for width in 0..new_width { +// let center_x = (width as f64 + 0.5) / new_width as f64 * ori_width as f64; +// let filter_start = center_x - filter_len / 2.0; +// let start_idx = (filter_start - 0.5).ceil() as usize; + +// let mut value_sum = 0.0; +// let mut filter_sum = 0.0; + +// for i in 0..filter_len as usize { +// let input_x = start_idx + i; +// let weight = windowed_sinc( +// (input_x as f64 + 0.5 - center_x) * rate, +// (input_x as f64 + 0.5 - filter_start) / filter_len, +// ); +// value_sum += weight * data[[height, input_x.clamp(0, ori_width - 1)]].as_(); +// filter_sum += weight; +// } + +// result[[height, width]] = V::from_f64(value_sum / filter_sum).unwrap(); +// } +// }); +// result +// } + +// pub struct LevelData( +// pub Quadtree>>, +// ); + +// impl LevelData +// where +// T: Num + Clone + AsPrimitive + FromPrimitive + Debug + PartialEq + PartialOrd, +// { +// fn value( +// level_data: Vec>>, +// level_num: usize, +// ) -> Vec>> { +// if level_num == 0 { +// return level_data; +// } + +// let mut result: Vec>> = +// Vec::with_capacity(level_data.len() * 4); + +// let results = level_data +// .iter() +// .flat_map(|v| v.split().into_iter().map(|x| x.value_to_owned())); + +// result.extend(results); + +// return Self::value(result, level_num - 1); +// } + +// fn new(data: &RadarData2d>, level: usize, rate: f64) -> Self { +// // let rate = 1.0 / level as f64; +// let resampled = data.resample(rate, rate, 2.0).unwrap(); +// let blocks = Self::value(vec![resampled], level); +// let mut tree: Quadtree>> = +// quadtree_rs::Quadtree::new(level); + +// blocks.into_iter().for_each(|block| { +// tree.insert( +// AreaBuilder::default() +// .anchor(quadtree_rs::point::Point { +// x: *block.dim1.first().unwrap() as i64, +// y: *block.dim2.first().unwrap() as i64, +// }) +// .dimensions((block.dim1.len() as i64, block.dim2.len() as i64)) +// .build() +// .unwrap(), +// block, +// ); +// }); + +// Self(tree) +// } +// } + +// pub fn levels(data: Radar2d, levels: usize) -> Vec> +// where +// T: Num + Clone + AsPrimitive + FromPrimitive + Debug, +// T: PartialEq + PartialOrd, +// { +// let numerator = 1.0 / levels as f64; +// (0..levels) +// .into_iter() +// .map(|level| LevelData::new(&data, level + 1, 1.0 - level as f64 * numerator)) +// .collect() +// } + +#[inline] +fn windowed_sinc(x: f64, y: f64) -> f64 { + let x = x * PI; + let sinc = if x != 0.0 { f64::sin(x) / x } else { 1.0 }; + let window = if 0f64 <= y && y <= 1.0 { + 1.0 - (y - 0.5).abs() * 2.0 + } else { + 0f64 + }; + sinc * window } - -pub type Radar2dRef = RadarData2d>; diff --git a/src/main.rs b/src/main.rs index 78ecc14..671cb6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,7 @@ use data::mapper::Mapper; use data::{Npz, Radar2d}; -use glib::{timeout_add, timeout_add_local}; -use glib_macros::clone; -use gtk::{ - gio, glib, style_context_add_provider_for_display, Application, ApplicationWindow, CssProvider, - FontButton, GestureDrag, -}; -use gtk::{prelude::*, DrawingArea}; +use gtk::prelude::*; +use gtk::{gio, glib, Application, ApplicationWindow}; use std::ptr; mod data; mod monitor; @@ -15,7 +10,6 @@ mod render; mod tree; mod window; use monitor::Monitor; -use ndarray::parallel::prelude::{IntoParallelIterator, ParallelIterator}; use painter::wgs84::{LatLonCoord, Mercator, ProjectionS, Range}; use render::{BackgroundConfig, BackgroundWidget, ForegroundConfig, ForegroundWidget, Render}; @@ -63,17 +57,19 @@ fn build_ui(app: &Application) { let foreground_widget = ForegroundWidget::new(foreground_config); let render = Render::new(background_widget, foreground_widget); - let path = "/Users/ruomu/test2.npz"; + let path = "/home/tsuki/projects/radar-g/test2.npz"; let data = Radar2d::::load(path, Npz).unwrap(); let projection = Mercator::new(); - let mapper: Mapper = projection.into(); + let mut mapper: Mapper = projection.into(); + mapper.set_lat_range(29.960..30.764); + mapper.set_lon_range(120.038..120.965); render.set_mapper(mapper); let monitor = Monitor::new(render); - monitor.load_data_2d(data); + monitor.load_data_2d(data).unwrap(); window.set_child(Some(&monitor)); window.set_default_width(1000); diff --git a/src/monitor/mod.rs b/src/monitor/mod.rs index e793004..c29225f 100644 --- a/src/monitor/mod.rs +++ b/src/monitor/mod.rs @@ -2,13 +2,14 @@ mod imp; use crate::data::RadarData2d; use crate::render::Render; use glib::clone; -use glib::{clone::Downgrade, subclass::prelude::*}; +use glib::subclass::prelude::*; use gtk::glib; use gtk::traits::WidgetExt; -use gtk::{EventController, EventControllerScrollFlags, Inhibit}; -use num_traits::Num; +use gtk::{EventControllerScrollFlags, Inhibit}; +use num_traits::{AsPrimitive, FromPrimitive, Num}; use proj::{Proj, ProjError}; use std::borrow::Borrow; +use std::fmt::Debug; glib::wrapper! { pub struct Monitor(ObjectSubclass) @@ -52,7 +53,14 @@ impl Monitor { pub fn load_data_2d(&self, data: RadarData2d) -> Result<(), ProjError> where - T: Num + Clone + PartialEq + PartialOrd, + T: Num + + Clone + + PartialEq + + PartialOrd + + AsPrimitive + + AsPrimitive + + Debug + + FromPrimitive, Raw: ndarray::Data + Clone + ndarray::RawDataClone, { let renderer = self.imp().renderer.borrow(); diff --git a/src/render/foreground/imp.rs b/src/render/foreground/imp.rs index a4b8ecf..d897c29 100644 --- a/src/render/foreground/imp.rs +++ b/src/render/foreground/imp.rs @@ -29,6 +29,7 @@ pub struct ForegroundWidget { pub(super) config: RefCell, pub(super) dim1: RefCell>>, pub(super) dim2: RefCell>>, + pub(super) data: RefCell>>, } #[glib::object_subclass] diff --git a/src/render/foreground/mod.rs b/src/render/foreground/mod.rs index 9b6cab7..2bf92de 100644 --- a/src/render/foreground/mod.rs +++ b/src/render/foreground/mod.rs @@ -1,9 +1,15 @@ mod imp; +use crate::tree::get; use crate::{data::mapper::Mapper, render::WindowCoord}; use femtovg::{renderer::OpenGl, Canvas, Path}; +use femtovg::{Color, Paint}; +use geo_types::LineString; use glib::subclass::types::ObjectSubclassIsExt; use gtk::{ffi::gtk_widget_get_width, glib, graphene::Rect, prelude::SnapshotExtManual}; -use ndarray::Array2; +use ndarray::parallel; +use ndarray::Slice; +use ndarray::{s, Array2, Axis, Zip}; +use std::cell::Ref; use std::ops::Range; pub use self::imp::ForegroundConfig; @@ -26,14 +32,101 @@ impl ForegroundWidget { this } - pub fn draw(&self, canvas: &mut Canvas, scale: f32, dpi: i32, mapper: &Mapper) { - let canvas_widht = canvas.width(); + pub fn draw(&self, canvas: &mut Canvas, scale: f32, dpi: i32, mapper: Ref<'_, Mapper>) { + let canvas_width = canvas.width(); let canvas_height = canvas.height(); let config = self.imp().config.borrow(); + + let dim1 = self.imp().dim1.borrow(); + let dim2 = self.imp().dim2.borrow(); + let data = self.imp().data.borrow(); + + let c = dim1.as_ref().unwrap().slice(s![..;3,..;3]); + let d = dim2.as_ref().unwrap().slice(s![..;3,..;3]); + let e = data.as_ref().unwrap().slice(s![..;3,..;3]); + + let levels: Vec = vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65]; + + let colors = vec![ + Color::rgb(0, 172, 164), + Color::rgb(192, 192, 254), + Color::rgb(122, 114, 238), + Color::rgb(30, 38, 208), + Color::rgb(166, 252, 168), + Color::rgb(0, 234, 0), + Color::rgb(16, 146, 26), + Color::rgb(252, 244, 100), + Color::rgb(200, 200, 2), + Color::rgb(140, 140, 0), + Color::rgb(254, 172, 172), + Color::rgb(254, 100, 92), + Color::rgb(238, 2, 48), + Color::rgb(212, 142, 254), + Color::rgb(170, 36, 250), + ]; + + Zip::from(c).and(d).and(e).for_each(|lon, lat, d| { + if *d < -5 || *d > 70 { + return; + } + + let left_bottom = mapper.map((*lon, *lat)).unwrap(); + let right_top = mapper.map((lon + 0.003, lat + 0.003)).unwrap(); + + // let (lon1, lat1) = ( + // left_bottom.0 * canvas_width as f64, + // left_bottom.1 * canvas_height as f64, + // ); + + let color = get(&levels, &colors, *d); + // + // let (lon2, lat2) = ( + // right_top.0 * canvas_width as f64, + // right_top.1 * canvas_height as f64, + // ); + + let line_string: LineString = vec![ + (left_bottom.0, left_bottom.1), + (right_top.0, left_bottom.1), + (right_top.0, right_top.1), + (left_bottom.0, right_top.1), + (left_bottom.0, left_bottom.1), + ] + .into(); + + // let line_string: LineString = vec![ + // (lon1, lat1), + // (lon2, lat1), + // (lon2, lat2), + // (lon1, lat2), + // (lon1, lat1), + // ] + // .into(); + + let res = mapper.ring_map(&line_string).unwrap(); + + let mut path = Path::new(); + + path.move_to( + left_bottom.0 as f32 * canvas_width, + left_bottom.1 as f32 * canvas_height, + ); + + for p in line_string.points() { + // path.move_to(p.x() as f32 * canvas_width, p.y() as f32 * canvas_height); + path.line_to(p.x() as f32 * canvas_width, p.y() as f32 * canvas_height); + } + canvas.fill_path(&path, &Paint::color(color)); + }); + canvas.flush(); } pub(super) fn set_dims(&mut self, dims: (Array2, Array2)) { self.imp().dim1.replace(Some(dims.0)); self.imp().dim2.replace(Some(dims.1)); } + + pub(super) fn set_data(&mut self, data: Array2) { + self.imp().data.replace(Some(data)); + } } diff --git a/src/render/imp.rs b/src/render/imp.rs index 83ed647..0f0e39b 100644 --- a/src/render/imp.rs +++ b/src/render/imp.rs @@ -51,10 +51,10 @@ impl ObjectImpl for Render { self.parent_constructed(); let area = self.obj(); area.set_has_stencil_buffer(true); - area.add_tick_callback(|area, _| { - area.queue_render(); - glib::Continue(true) - }); + // area.add_tick_callback(|area, _| { + // area.queue_render(); + // glib::Continue(true) + // }); } } @@ -96,6 +96,13 @@ impl GLAreaImpl for Render { .borrow() .draw(canvas, self.scale.borrow().clone(), dpi); + self.foreground.borrow().draw( + canvas, + self.scale.borrow().clone(), + dpi, + self.mapper.borrow(), + ); + canvas.flush(); true diff --git a/src/render/mod.rs b/src/render/mod.rs index 5937255..6d4c6ca 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -2,13 +2,16 @@ mod background; mod foreground; mod imp; +use std::fmt::Debug; + use crate::data::{mapper::Mapper, RadarData2d}; pub use self::background::{BackgroundConfig, BackgroundWidget}; pub use self::foreground::{ForegroundConfig, ForegroundWidget}; +use crate::data::DownSampleMeth; pub use glib::subclass::prelude::*; -use ndarray::{self, s, Axis, Dimension, Ix2, Zip}; -use num_traits::Num; +use ndarray::{self, s, Array2, Axis, Dimension, Ix2, Zip}; +use num_traits::{AsPrimitive, FromPrimitive, Num}; use proj::ProjError; pub(super) type WindowCoord = (f32, f32); @@ -39,17 +42,30 @@ impl Render { pub(super) fn load_data_2d(&self, data: RadarData2d) -> Result<(), ProjError> where - T: Num + Clone + PartialEq + PartialOrd, + T: Num + + Clone + + PartialEq + + PartialOrd + + AsPrimitive + + AsPrimitive + + Debug + + FromPrimitive, Raw: ndarray::Data + Clone + ndarray::RawDataClone, { assert!(data.dim1.shape().len() == data.dim2.shape().len()); + data.downsample((801 / 2, 947 / 2), DownSampleMeth::VAR); + let meshed = data.map_by_fn(|(x, y)| Ok((x, y)))?; + let d = data.data.to_owned().map(|x| x.as_()); self.imp() .foreground .borrow_mut() .set_dims((meshed.dim1, meshed.dim2)); + + self.imp().foreground.borrow_mut().set_data(d); + Ok(()) } } diff --git a/src/tree.rs b/src/tree.rs index 73700d6..a163714 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -1,7 +1,7 @@ -use gtk::gdk::RGBA; +use femtovg::Color; use num_traits::Num; -pub fn get(levels: &Vec, colors: &Vec, v: T) -> RGBA +pub fn get(levels: &Vec, colors: &Vec, v: T) -> V where T: Num + PartialOrd + Copy, {