diff --git a/gi/src/graphics/geoquadmesh.rs b/gi/src/graphics/geoquadmesh.rs index 6ddbc7e..06daa8f 100644 --- a/gi/src/graphics/geoquadmesh.rs +++ b/gi/src/graphics/geoquadmesh.rs @@ -1,9 +1,11 @@ use glow::HasContext; +use log::*; use radarg_core::{CoordType, ProbeDataType, RadarGridData}; use crate::{ components::{Program, Shader}, errors::*, + match_array_type, pg::Attach, shaders::geoquadmesh::{GeoQuadMeshFragment, GeoQuadMeshVertex}, }; @@ -33,7 +35,7 @@ impl GeoQuadMesh { let lat_dpi = config.lat_dpi; let alt_dpi = config.alt_dpi; - let location = self.program.get_uniform_location(gl, "data_info"); + let data_info = self.program.get_uniform_location(gl, "data_info"); self.cmap .set_range(config.color_range[0], config.color_range[1]); @@ -44,10 +46,16 @@ impl GeoQuadMesh { let location_r = self.program.get_uniform_location(gl, "R"); let location_layer = self.program.get_uniform_location(gl, "layer"); let tex_conf = self.program.get_uniform_location(gl, "tex_conf"); + let data_shape = self.program.get_uniform_location(gl, "data_shape"); + let dpi = self.program.get_uniform_location(gl, "dpi"); unsafe { + let offset = config.offset; + let scale = config.scale; + let min = config.min; + let max = config.max; gl.uniform_1_f32(location_r.as_ref(), 6378137.0); - gl.uniform_4_f32(location.as_ref(), lon_dpi, lat_dpi, alt_dpi, 0.0); + gl.uniform_4_f32(data_info.as_ref(), offset, scale, min, max); gl.uniform_1_f32(location_layer.as_ref(), config.layer as f32); let lon_s = config.lon_range[0]; @@ -55,6 +63,11 @@ impl GeoQuadMesh { let lat_s = config.lat_range[0]; let lat_e = config.lat_range[1]; gl.uniform_4_f32(tex_conf.as_ref(), lon_s, lon_e, lat_s, lat_e); + + // gl.uniform_3_f32(tex_shape.as_ref(), config.alt_range[1], config.lat_range[1], config.lon_range[1]); + + gl.uniform_3_f32_slice(data_shape.as_ref(), &config.data_shape); + gl.uniform_3_f32(dpi.as_ref(), config.alt_dpi, config.lat_dpi, config.lon_dpi); } } @@ -70,7 +83,9 @@ impl GeoQuadMesh { [f32; 2], [f32; 2], [f32; 3], + [f32; 3], ProbeDataType, + f64, )> { if data.coord_type().is_none() { return Err(Error::InvalidDataType(format!("Invalid CoordType"))); @@ -91,16 +106,33 @@ impl GeoQuadMesh { let alt_dpi = (hgt[1] - hgt[0]); (Some([hgt_start, hgt_end]), alt_dpi) } else { - (None, 0.0) + (None, 1.0) }; let data_type = data.data_type(); + + let fill_value = data.info.fill_value; + + let data_shape = data.data.shape(); + + let data_shape = if data_shape.len() == 3 { + [ + data_shape[0] as f32, + data_shape[1] as f32, + data_shape[2] as f32, + ] + } else { + [1.0, data_shape[0] as f32, data_shape[1] as f32] + }; + Ok(( hgt_range, [lat_start, lat_end], [lon_start, lon_end], [alt_dpi as f32, lat_dpi as f32, lon_dpi as f32], + data_shape, data_type, + fill_value, )) } _ => Err(Error::InvalidDataType(format!("Invalid CoordType"))), @@ -111,15 +143,21 @@ impl GeoQuadMesh { #[derive(Debug, Clone, Default)] pub struct GeoQuadMeshConfig { pub unvalid_value: f32, - pub layer: usize, + pub layer: f32, + pub max_layer: usize, pub colors: Vec<[u8; 4]>, pub color_range: [f32; 2], pub lon_dpi: f32, pub lat_dpi: f32, pub alt_dpi: f32, + pub data_shape: [f32; 3], pub lat_range: [f32; 2], pub lon_range: [f32; 2], pub alt_range: [f32; 2], + pub scale: f32, + pub offset: f32, + pub min: f32, + pub max: f32, } impl Graphics for GeoQuadMesh { @@ -137,7 +175,7 @@ impl Graphics for GeoQuadMesh { fn draw(&self, gl: &glow::Context, count: i32) -> Result<()> { unsafe { - gl.draw_arrays(glow::TRIANGLE_STRIP_ADJACENCY, 0, count); + gl.draw_arrays(glow::TRIANGLE_STRIP, 0, count); } Ok(()) } @@ -276,8 +314,13 @@ impl AttaWithBuffer for GeoQuadMesh { (attach.textures.as_ref()).map(|t| t.native()), ); - let _data = &data.data; - let shape = _data.shape(); + let max_depth_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE); + info!("Max 3D Texture Size: {}", max_depth_size); + + gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); + + let data = &data.data; + let shape = data.shape(); let (depth, height, width) = if shape.len() == 2 { (1i32, shape[0] as i32, shape[1] as i32) @@ -285,19 +328,39 @@ impl AttaWithBuffer for GeoQuadMesh { (shape[0] as i32, shape[1] as i32, shape[2] as i32) }; - let pixels: &[u8] = cast_slice(_data.as_slice().unwrap()); + info!("Data Shape: {:?}", shape); + + // let tex_width = width / 4 + 1; + // let tex_height = height / 4 + 1; + + let fill_value = config.unvalid_value; + let min_value = config.min; + let max_value = config.max; + + let v = data.scale_offset_to_pixel(fill_value, min_value, max_value); + + let pixel_num = (v.len() / 4 + 1) as f32; + let edge_len = (pixel_num.powf(1.0 / 3.0) + 1.0) as usize; + + let real_size = edge_len * edge_len * edge_len * 4; + let data_size = v.len(); + let padding_size = real_size - data_size; + + let mut pixels = vec![0u8; real_size as usize]; + &pixels[..data_size].copy_from_slice(cast_slice(v.as_slice().unwrap())); + attach.texture_shape = Some([edge_len as f32; 3]); gl.tex_image_3d( glow::TEXTURE_3D, 0, - glow::R8 as i32, - width, - height, - depth, + glow::RGBA as i32, + edge_len as i32, + edge_len as i32, + edge_len as i32, 0, - glow::RED, + glow::RGBA, glow::UNSIGNED_BYTE, - Some(pixels), + Some(pixels.as_slice()), ); } diff --git a/gi/src/graphics/mod.rs b/gi/src/graphics/mod.rs index 064f5c7..e3767d0 100644 --- a/gi/src/graphics/mod.rs +++ b/gi/src/graphics/mod.rs @@ -20,6 +20,32 @@ use crate::{ use glow::{HasContext, NativeBuffer, NativeTexture, NativeVertexArray}; +#[macro_export] +macro_rules! match_array_type { + ($array:ident, $just_do_it:expr) => { + use radarg_core::ArrayData; + match $array { + ArrayData::U8(v) => $just_do_it(v), + + ArrayData::U32(v) => $just_do_it(v), + + ArrayData::U64(v) => $just_do_it(v), + + ArrayData::I8(v) => $just_do_it(v), + + ArrayData::I16(v) => $just_do_it(v), + + ArrayData::I32(v) => $just_do_it(v), + + ArrayData::I64(v) => $just_do_it(v), + + ArrayData::F32(v) => $just_do_it(v), + + ArrayData::F64(v) => $just_do_it(v), + } + }; +} + pub trait Graphics { const id: &'static str; type Config; diff --git a/gi/src/graphics/ppi.rs b/gi/src/graphics/ppi.rs index 13da5c7..957ed9c 100644 --- a/gi/src/graphics/ppi.rs +++ b/gi/src/graphics/ppi.rs @@ -208,7 +208,7 @@ impl AttaWithBuffer for PPI { for r_idx in 0..r_len { let azi = *azimuth.get(azi_idx).unwrap() as f32; let r = *range.get(r_idx).unwrap() as f32 / last_range; - let data = &data.data; + let data = &data.data.cast_to::(); let dt = data.get([layer, azi_idx, r_idx]).unwrap(); vertices.extend([r, azi, ele, *dt]); } diff --git a/gi/src/pg/mod.rs b/gi/src/pg/mod.rs index f62eb7c..90b9c41 100644 --- a/gi/src/pg/mod.rs +++ b/gi/src/pg/mod.rs @@ -43,6 +43,7 @@ static MODULE_PACKAGE_ID: AtomicUsize = AtomicUsize::new(0); #[derive(Debug)] pub enum SideBarInputMsg { Packages(Vec<(String, Rc>)>), + ClearPackages, SwitchTo(gtk::glib::GString), Refresh, None, @@ -143,7 +144,7 @@ macro_rules! impl_module_package { } } - #[derive(Debug)] + // #[derive(Debug)] pub enum _ModulePackage { $( $b($t), @@ -183,13 +184,19 @@ macro_rules! impl_module_package { } } - #[derive(Debug)] + // #[derive(Debug)] pub struct ModulePackage { id: usize, pub need_update: bool, modules: _ModulePackage, } + impl std::fmt::Debug for ModulePackage { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ModulePackage {{ id: {}, need_update: {} }}", self.id, self.need_update) + } + } + impl ModulePackage { pub fn component_builder(&self) -> ComponentBuilders { diff --git a/gi/src/pg/modules/geoquadmesh.rs b/gi/src/pg/modules/geoquadmesh.rs index b764484..973aeb7 100644 --- a/gi/src/pg/modules/geoquadmesh.rs +++ b/gi/src/pg/modules/geoquadmesh.rs @@ -16,11 +16,13 @@ use relm4::{ gtk::{self, prelude::*}, ComponentParts, SimpleComponent, }; +use toml::value; use core::f32; use glow::HasContext; use std::{ cell::{RefCell, RefMut}, + f32::consts::E, rc::Rc, sync::Arc, }; @@ -120,7 +122,7 @@ impl<'b, 'a: 'b> GeoQuadMeshModule<'b, 'a> { config: &GeoQuadMeshModuleConfig, ) -> Result<()> { self.geo_quad_mesh_program - .bake(&self.gl, data, &config.to_quad_config(), attach) + .bake(&self.gl, data, &mut config.to_quad_config(), attach) } fn bind_line_pg( @@ -140,6 +142,29 @@ impl<'b, 'a: 'b> GeoQuadMeshModule<'b, 'a> { ) -> Result<()> { Ok(()) } + + fn bind_attach_tex(&mut self, attach: &mut Attach) -> Result<()> { + if let Some(tex) = attach.textures.as_ref() { + unsafe { + self.gl.active_texture(glow::TEXTURE1); + self.gl.bind_texture(glow::TEXTURE_3D, Some(tex.native())); + let loc = self + .geo_quad_mesh_program + .program() + .get_uniform_location(&self.gl, "data_tex"); + self.gl.uniform_1_i32(loc.as_ref(), 1); + + let tex_shape = self + .geo_quad_mesh_program + .program() + .get_uniform_location(&self.gl, "tex_shape"); + + self.gl + .uniform_3_f32_slice(tex_shape.as_ref(), &attach.texture_shape.unwrap()); + } + } + Ok(()) + } } impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { @@ -155,12 +180,6 @@ impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { operation: &Operation, viewport: &ViewPort, ) -> Result<()> { - unsafe { - let err = self.gl.get_error(); - if err != glow::NO_ERROR { - panic!("Error: {}", err); - } - } // PPI Program let data = &cursor.data; let mut config = &mut cursor.ppi_config.borrow_mut(); @@ -169,25 +188,17 @@ impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { // Deal with the operation operation.attach_with_program(&self.gl, self.geo_quad_mesh_program.program()); let quad_attach = &mut cursor.quad_attach; - unsafe { - let err = self.gl.get_error(); - if err != glow::NO_ERROR { - panic!("Error: {}", err); - } - } // Update the config self.geo_quad_mesh_program .set_config(&self.gl, &config.to_quad_config())?; - unsafe { - let err = self.gl.get_error(); - if err != glow::NO_ERROR { - panic!("Error: {}", err); - } - } // Quad Draw quad_attach.bind_self(self.geo_quad_mesh_program.program_ref()); + // Bind the texture + self.bind_attach_tex(quad_attach)?; + + // Draw the quad self.geo_quad_mesh_program .draw(&self.gl, quad_attach.len())?; @@ -207,11 +218,9 @@ impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { let mut quad_attach = Attach::new(self.gl.clone(), vao, vbo, ebo, texs, None); // Get the data info - let (hgt_range, lat_range, lon_range, dpi, t) = + let (hgt_range, lat_range, lon_range, dpi, data_shape, t, fill_value) = self.geo_quad_mesh_program.data_info(&data)?; - println!("name: {}", data.info.value_name); - // Find the color map let cmap = setting.find(&t); @@ -232,6 +241,10 @@ impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { let (vao, vbo, ebo, texs) = self.text_program.init(&self.gl); let mut tick_attach = Attach::new(self.gl.clone(), vao, vbo, ebo, texs, None); + let value_range = cmap.value_range(); + let offset = -fill_value; + let scale = value_range[1] / value_range[0]; + let mut config = GeoQuadMeshModuleConfig::default(); config.alt_dpi = dpi[0]; config.lat_dpi = dpi[1]; @@ -242,9 +255,16 @@ impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { config.hgt_range = hgt_range.unwrap_or_default(); config.colors = cmap.color().unwrap(); config.color_range = cmap.value_range(); + config.unvalid_value = fill_value as f32; + config.scale = scale; + config.offset = offset as f32; + config.min = value_range[0] as f32; + config.max = value_range[1] as f32; + config.data_shape = data_shape; + config.max_layer = data_shape[0] as usize; // Bind the data - self.bind_geo_quad_mesh_pg(&mut quad_attach, data, &config); + self.bind_geo_quad_mesh_pg(&mut quad_attach, data, &config)?; // self.bind_line_pg(&mut line_attach, &data, &config); // self.bind_tick(&mut tick_attach, &data.borrow(), &config); @@ -272,7 +292,7 @@ impl<'b, 'a: 'b> Module for GeoQuadMeshModule<'b, 'a> { } } -#[derive(Debug)] +// #[derive(Debug)] pub struct GeoQuadMeshPackage { draw_helper: bool, ppi_config: Rc>, @@ -308,7 +328,7 @@ pub struct GeoQuadMeshModuleConfig { pub line_color: [f32; 4], pub line_width: f32, pub line_antialias: f32, - pub layer: usize, + pub layer: f32, pub colors: Vec<[u8; 4]>, pub color_range: [f32; 2], pub is_three_d: bool, @@ -334,6 +354,16 @@ pub struct GeoQuadMeshModuleConfig { pub alt_dpi: f32, #[do_not_track] pub lon_dpi: f32, + #[do_not_track] + pub scale: f32, + #[do_not_track] + pub offset: f32, + #[do_not_track] + pub min: f32, + #[do_not_track] + pub max: f32, + #[do_not_track] + pub data_shape: [f32; 3], } impl Default for GeoQuadMeshModuleConfig { @@ -343,7 +373,7 @@ impl Default for GeoQuadMeshModuleConfig { line_color: [1.0, 1.0, 1.0, 1.0], line_width: 1.5, line_antialias: 0.5, - layer: 0, + layer: 0.0, colors: vec![], color_range: [0.0, 0.0], is_three_d: true, @@ -358,6 +388,11 @@ impl Default for GeoQuadMeshModuleConfig { lat_range: [0.0, 0.0], lon_range: [0.0, 0.0], hgt_range: [0.0, 0.0], + scale: 1.0, + offset: 0.0, + min: 0.0, + max: 0.0, + data_shape: [0.0, 0.0, 0.0], } } } @@ -375,6 +410,12 @@ impl GeoQuadMeshModuleConfig { lat_range: self.lat_range, lon_range: self.lon_range, alt_range: self.hgt_range, + scale: self.scale, + offset: self.offset, + min: self.min, + max: self.max, + data_shape: self.data_shape, + max_layer: self.max_layer, } } @@ -426,6 +467,27 @@ impl SimpleComponent for GeoQuadMeshModuleConfigComponent { } }, + adw::SpinRow { + set_title: "Layer", + set_digits: 0, + set_numeric: true, + set_snap_to_ticks: true, + #[wrap(Some)] + set_adjustment=>k::Adjustment::new( + init_config.layer as f64, + init_config.hgt_range[0] as f64, + init_config.hgt_range[1] as f64, + init_config.alt_dpi as f64, + 1.0, + 1.0, + ), + connect_value_notify[sender, config_ref] => move |this| { + let num = this.value() as f32; + config_ref.borrow_mut().set_layer(num); + sender.output(OutputMsg::Refresh); + }, + } + } } diff --git a/gi/src/pg/modules/mod.rs b/gi/src/pg/modules/mod.rs index 38b15de..f79ffb1 100644 --- a/gi/src/pg/modules/mod.rs +++ b/gi/src/pg/modules/mod.rs @@ -35,6 +35,7 @@ pub(crate) struct Attach { pub vbo: RcGlRcBuffer, pub ebo: Option, pub textures: Option>, + pub texture_shape: Option<[f32; 3]>, pub len: i32, } @@ -58,6 +59,7 @@ impl Attach { vbo, ebo, textures, + texture_shape: None, len: len.unwrap_or(0), } } @@ -68,15 +70,6 @@ impl Attach { if let Some(ebo) = self.ebo.as_ref() { ebo.bind(glow::ELEMENT_ARRAY_BUFFER); } - - if let Some(tex) = self.textures.as_ref() { - unsafe { - self.gl.active_texture(glow::TEXTURE0); - self.gl.bind_texture(glow::TEXTURE_3D, Some(tex.native())); - let loc = program.get_uniform_location(&self.gl, "_texture"); - self.gl.uniform_1_i32(loc.as_ref(), 0); - } - } } fn unbind_self(&self) { diff --git a/gi/src/pg/modules/ppi.rs b/gi/src/pg/modules/ppi.rs index a7f8b1e..8b44aac 100644 --- a/gi/src/pg/modules/ppi.rs +++ b/gi/src/pg/modules/ppi.rs @@ -434,7 +434,7 @@ impl<'b, 'a: 'b> Module for PPIModule<'b, 'a> { } } -#[derive(Debug)] +// #[derive(Debug)] pub struct PPIPackage { draw_helper: bool, ppi_config: Rc>, diff --git a/gi/src/shaders/colormap.rs b/gi/src/shaders/colormap.rs index 3cb2343..63ed669 100644 --- a/gi/src/shaders/colormap.rs +++ b/gi/src/shaders/colormap.rs @@ -39,7 +39,7 @@ impl ColorMap { float v = clamp((value - vmin), vmin, vmax) / (vmax - vmin); float idx = find_idx(v); vec4 result = texture(colormap, idx); - return result; + return vec4(result.rgb, 1.0); } }; diff --git a/gi/src/shaders/geoquadmesh.rs b/gi/src/shaders/geoquadmesh.rs index c16a775..4c04ba0 100644 --- a/gi/src/shaders/geoquadmesh.rs +++ b/gi/src/shaders/geoquadmesh.rs @@ -9,7 +9,7 @@ use glsl_quasiquote::glsl; use super::proj::Mercator; pub struct GeoQuadMeshVertex(pub ShaderStage); -pub struct GeoQuadMeshGeom(pub ShaderStage); +// pub struct GeoQuadMeshGeom(pub ShaderStage); pub struct GeoQuadMeshFragment(pub ShaderStage); impl GeoQuadMeshVertex { @@ -46,9 +46,15 @@ impl GeoQuadMeshFragment { let raw = glsl! { // lon_s,lon_e, lat_s, lat_e uniform vec4 tex_conf; - - // lon_reso, lat_reso, alt_reso + // hgt, lat, lon + uniform vec3 tex_shape; + // offset, scale, min, max uniform vec4 data_info; + // data shape + uniform vec3 data_shape; + + // hgt, lat, lon + uniform vec3 dpi; // Current layer uniform float layer; @@ -57,25 +63,63 @@ impl GeoQuadMeshFragment { in vec2 projected_meter; // data array - uniform sampler3D _texture; + uniform sampler3D data_tex; void main() { vec2 lon_lat = mercatorInverse(projected_meter); - vec3 tex_coord = vec3(lon_lat.x / tex_conf.z, lon_lat.y / tex_conf.w, layer / tex_conf.x); + float x = round((lon_lat.x - tex_conf.x) / dpi.z); + float y = round((lon_lat.y - tex_conf.z) / dpi.y); + float z = floor(layer / dpi.x); - float value = texture(_texture, tex_coord).r; + uint raw_loc = uint(z * (data_shape.y * data_shape.z) + y * data_shape.z + x); + + uint loc = raw_loc / 4u; + uint channel = raw_loc % 4u; + + uint tex_depth = uint(tex_shape.x); + uint tex_height = uint(tex_shape.y); + uint tex_width = uint(tex_shape.z); + + float tz = float(loc / (tex_width * tex_height)); + float ty = float((loc % (tex_height * tex_width) / tex_width)); + float tx = float(loc % tex_width); + + vec3 tex_coord = vec3(tx / tex_shape.z, ty / tex_shape.y, tz / tex_shape.x); + + vec4 _value = texture(data_tex, tex_coord); + + float value = 0.0; + + switch (channel) { + case 0: + value = _value.r; + break; + case 1: + value = _value.g; + break; + case 2: + value = _value.b; + break; + case 3: + value = _value.a; + break; + } + + float min = data_info.z; + float max = data_info.w; + + if (abs(value - 0.0) < 0.0001) { + discard; + } + + // Real value + value = value * 255.0 / 254.0 * (max - min); vec4 color = linear_colormap(value); - fragColor = vec4(1.0,1.0,1.0,1.0); - - // if (color.a < 0.1) { - // discard; - // } else { - // fragColor = color; - // } + fragColor = color; } }; diff --git a/loaders/etws_loader/src/lib.rs b/loaders/etws_loader/src/lib.rs index 8cadf98..26a6144 100644 --- a/loaders/etws_loader/src/lib.rs +++ b/loaders/etws_loader/src/lib.rs @@ -106,7 +106,7 @@ impl DataLoaderPlugin for ETWSLoader { let data_type = data_type!( value_key, { "ET" => ET }, - { "DBZ" | "CR" | "FR" | "R" => DBZ}, + { "DBZ" | "CR" | "FR" | "R" | "CR0" | "CR1" | "CR2" => DBZ}, { "VIL" => VIL}, { "EB" => EB}, { "V" => V}, @@ -165,7 +165,7 @@ impl DataLoaderPlugin for ETWSLoader { let data_type = data_type!( k, { "ET" => ET }, - { "DBZ" | "CR" | "FR" | "R" => DBZ}, + { "DBZ" | "CR" | "FR" | "R" | "CR0" | "CR1" | "CR2" => DBZ}, { "VIL" => VIL}, { "EB" => EB}, { "V" | "VEL" => V}, diff --git a/radar-g/src/components/app.rs b/radar-g/src/components/app.rs index 622920c..eacad3c 100644 --- a/radar-g/src/components/app.rs +++ b/radar-g/src/components/app.rs @@ -71,6 +71,7 @@ pub enum AppMsg { CloseRequest, Close, OpenFileDialog, + Packages { clear: bool }, } #[tracker::track] pub struct AppModel { @@ -221,6 +222,13 @@ impl Component for AppModel { .forward(sender.input_sender(), |msg| match msg { SideBarOutputMsg::Dialog(widget) => AppMsg::OpenDialog { widget }, SideBarOutputMsg::QueueDraw => AppMsg::Refresh, + SideBarOutputMsg::Packages { clear } => { + if clear { + AppMsg::Packages { clear: true } + } else { + AppMsg::Refresh + } + } _ => AppMsg::Close, }); @@ -404,7 +412,8 @@ impl Component for AppModel { let mut datapool = self.file_pool.borrow_mut(); match datapool.get_or_load(path) { Ok(data) => { - info!("data: {}", data); + info!("data: {:?}", data); + _sender.input(AppMsg::Packages { clear: true }); _sender.input(AppMsg::FileIO { typ: FileIOType::Open(data), }); @@ -423,6 +432,10 @@ impl Component for AppModel { } => self.render.emit(MonitorInputMsg::PushData(data)), AppMsg::Refresh => self.render.emit(MonitorInputMsg::QueueDraw), + + AppMsg::Packages { clear } => { + self.render.emit(MonitorInputMsg::Packages { clear: true }); + } _ => {} } self.update_view(widgets, _sender); diff --git a/radar-g/src/components/monitor/messages.rs b/radar-g/src/components/monitor/messages.rs index e066e5d..a95021a 100644 --- a/radar-g/src/components/monitor/messages.rs +++ b/radar-g/src/components/monitor/messages.rs @@ -10,6 +10,7 @@ pub enum MonitorInputMsg { Prepare(Vec>), KeyPress(u32), KeyRelease(u32), + Packages { clear: bool }, QueueDraw, None, } @@ -27,6 +28,10 @@ impl Debug for MonitorInputMsg { MonitorInputMsg::KeyPress(key) => write!(f, "MonitorInputMsg::Key({:?})", key), MonitorInputMsg::KeyRelease(key) => write!(f, "MonitorInputMsg::KeyRelease({:?})", key), MonitorInputMsg::PushData(data) => write!(f, "MonitorInputMsg::PushData({:?})", data), + + &MonitorInputMsg::Packages { clear } => { + write!(f, "MonitorInputMsg::Packages {{ clear: {} }}", clear) + } MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"), } } diff --git a/radar-g/src/components/monitor/monitor.rs b/radar-g/src/components/monitor/monitor.rs index ccf3a36..aa001d2 100644 --- a/radar-g/src/components/monitor/monitor.rs +++ b/radar-g/src/components/monitor/monitor.rs @@ -236,6 +236,12 @@ impl Component for MonitorModel { MonitorInputMsg::KeyRelease(key) => { widgets.renderer.set_key_released(key); } + + MonitorInputMsg::Packages { clear } => { + if clear { + self.update_module_packages(|p| p.clear()); + } + } MonitorInputMsg::None => {} _ => {} } diff --git a/radar-g/src/components/sidebar/sidebar.rs b/radar-g/src/components/sidebar/sidebar.rs index b2c3ff0..e386cce 100644 --- a/radar-g/src/components/sidebar/sidebar.rs +++ b/radar-g/src/components/sidebar/sidebar.rs @@ -38,6 +38,7 @@ pub struct SideBarModel { #[derive(Debug)] pub enum SideBarOutputMsg { Dialog(Widget), + Packages { clear: bool }, QueueDraw, } @@ -76,6 +77,13 @@ impl Component for SideBarModel { set_transition_type:gtk::StackTransitionType::SlideLeftRight, set_transition_duration:200, set_hexpand:true, + }, + + gtk::Button { + set_label:"Clear", + connect_clicked[sender] => move |_| { + sender.input(SideBarInputMsg::ClearPackages); + } } } }, @@ -133,6 +141,14 @@ impl Component for SideBarModel { sender.output(SideBarOutputMsg::QueueDraw).unwrap(); } + SideBarInputMsg::ClearPackages => { + widgets.stack.remove_all(); + self.components.clear(); + widgets.dropdown.set_selected(gtk::INVALID_LIST_POSITION); + widgets.dropdown.set_model(None::<>k::StringList>); + sender.output(SideBarOutputMsg::Packages { clear: true }); + } + _ => {} } } diff --git a/radarg_core/src/datapool/mod.rs b/radarg_core/src/datapool/mod.rs index 3f55261..689211d 100644 --- a/radarg_core/src/datapool/mod.rs +++ b/radarg_core/src/datapool/mod.rs @@ -44,15 +44,15 @@ impl Deref for Value { } } -impl Display for Value { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for data in self.0.iter() { - writeln!(f, "{:?}", data)?; - } +// impl Display for Value { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// for data in self.0.iter() { +// writeln!(f, "{:?}", data)?; +// } - Ok(()) - } -} +// Ok(()) +// } +// } pub struct DataPool { plugin_manager: &'static PluginManager, diff --git a/radarg_core/src/radarg_data/mod.rs b/radarg_core/src/radarg_data/mod.rs index fce6fb9..c4909c9 100644 --- a/radarg_core/src/radarg_data/mod.rs +++ b/radarg_core/src/radarg_data/mod.rs @@ -1,3 +1,4 @@ +use num_traits::FromPrimitive; use std::{ fmt::Display, hash::Hash, @@ -14,13 +15,23 @@ use radarg_plugin_interface::{ static DATA_ID: AtomicUsize = AtomicUsize::new(0); -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Data { pub id: usize, pub description: String, _data: _Data, } +impl std::fmt::Debug for Data { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Data {{ id: {}, description: {}", + self.id, self.description + ) + } +} + impl PartialEq for Data { fn eq(&self, other: &Self) -> bool { self.id == other.id @@ -41,7 +52,7 @@ impl Display for Data { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub enum _Data { RadarGridData(Arc), JsonData, @@ -60,14 +71,14 @@ impl Display for _Data { } } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct RadarGridData { - pub data: ArrayD, + pub data: ArrayData, pub info: GridDataInfo, } impl RadarGridData { - pub fn get_data(&self) -> &ArrayD { + pub fn get_data(&self) -> &ArrayData { &self.data } @@ -195,7 +206,67 @@ pub enum ProbeDataType { } macro_rules! raw2new { - ($({$raw_bc:tt}),+, ($({$raw_rdt:tt}),+)) => { + ($({$raw_bc:tt | $typ:ty | $from:ident}),+, ($({$raw_rdt:tt}),+)) => { + + #[derive(Debug, Clone)] + pub enum ArrayData { + $( + $raw_bc(ArrayD<$typ>), + )+ + } + + impl ArrayData { + pub fn shape(&self) -> &[usize] { + match self { + $( + ArrayData::$raw_bc(v) => v.shape(), + )+ + } + } + + pub fn cast_to(&self) -> ArrayD { + match self { + $( + ArrayData::$raw_bc(v) => v.map(|v| T::$from(*v).unwrap()), + )+ + } + } + + pub fn scale_offset(&self, scale: f64, offset: f64) -> ArrayD{ + match self { + $( + ArrayData::$raw_bc(v) => v.mapv(|v| v as f32 * scale as f32 + offset as f32), + )+ + } + } + + pub fn scale_offset_to_pixel(&self, fill_value:f32, min:f32, max:f32) -> ArrayD{ + match self { + $( + ArrayData::$raw_bc(v) => v.mapv(|v| { + if (v as f32 - fill_value).abs() < 1e-6 { + 0 + } else { + let v = (v as f32 - min) / (max - min) * 254.0; + v as u8 + 1 + } + }), + )+ + } + } + + + $( + pub fn $raw_bc(&self) -> &ArrayD<$typ> { + match self { + ArrayData::$raw_bc(v) => v, + _ => panic!("Unsupported data type"), + } + } + )+ + + } + impl From for RadarGridData { fn from(raw: RawRadarGridData) -> Self { let RawRadarGridData { data, info } = raw; @@ -205,8 +276,7 @@ macro_rules! raw2new { let data = match data { $( $raw_bc(v) => { - let data = v.into_iter().map(|x| x as f32).collect(); - ArrayD::from_shape_vec(shape.clone(), data).unwrap() + ArrayData::$raw_bc(ArrayD::from_shape_vec(shape.clone(), v.to_vec()).unwrap()) } )+ _ => panic!("Unsupported data type"), @@ -243,16 +313,15 @@ macro_rules! raw2new { } raw2new!( - { F32 }, - { F64 }, - { I32 }, - { I16 }, - { F32 }, - { U64 }, - { U32 }, - { I8 }, - { U8 }, - { I64 }, + { F32 | f32 | from_f32 }, + { F64 | f64 | from_f64 }, + { I32 | i32 | from_i32 }, + { I16 | i16 | from_i16 }, + { U64 | u64 | from_u64 }, + { U32 | u32 | from_u32 }, + { I8 | i8 | from_i8 }, + { U8 | u8 | from_u8 }, + { I64 | i64 | from_i64 }, ( { R }, { V }, @@ -347,10 +416,5 @@ mod test { use super::Data; - fn test() { - let radar_data = RadarGridData { - data: ndarray::ArrayD::from_shape_vec(ndarray::IxDyn(&[1, 1]), vec![1.0]).unwrap(), - info: super::GridDataInfo::default(), - }; - } + fn test() {} }