use super::color_mapper::{BoundaryNorm, ColorMapper}; use crate::pipeline::element::{Target, TargetType}; use femtovg::ImageInfo; use femtovg::{ renderer::OpenGl, Canvas, ImageFlags, Paint, Path, PixelFormat::Rgba8, RenderTarget, }; use geo_types::LineString; use gl::types::GLvoid; use image::{imageops::resize, ImageBuffer, Rgba}; use ndarray::ArrayView2; use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps}; use std::{fmt::Debug, io::Cursor, marker::PhantomData}; use super::super::renders::DataRenderer; use super::super::{LayerImpl, Render}; use crate::{data::Radar2d, utils::meshgrid}; use crate::coords::cms::CMS; #[derive(Debug)] pub struct GridFieldRenderer where T: NumOps + PartialOrd + FromPrimitive + AsPrimitive, CMAP: ColorMapper, { cmap: CMAP, value_phantom: PhantomData, } impl, CMAP: ColorMapper> GridFieldRenderer { pub fn new(cmap: CMAP) -> Self { Self { cmap, value_phantom: PhantomData, } } fn draw_2d( &self, canvas: &mut femtovg::Canvas, cms: &CMS, data: ArrayView2, dims: (ArrayView2, ArrayView2), window_size: (f32, f32), fill_value: T, ) { let shape = data.shape(); let (rows, cols) = (shape[0], shape[1]); let (dim1, dim2) = dims; let d1_s = dim1[[0, 0]]; let d1_e = dim1[[0, cols - 1]]; let d2_s = dim2[[0, 0]]; let d2_e = dim2[[rows - 1, 0]]; for r in 0..rows - 1 { for c in 0..cols - 1 { let lb_lat = dim2[[r, c]]; let lb_lon = dim1[[r, c]]; let rt_lat = dim2[[r + 1, c + 1]]; let rt_lon = dim1[[r + 1, c + 1]]; let cell: LineString = vec![ (lb_lon, lb_lat), (rt_lon + 0.001, lb_lat), (rt_lon + 0.001, rt_lat), (lb_lon, rt_lat + 0.001), (lb_lon, lb_lat + 0.001), ] .into(); let v = &data[[r, c]]; let mapped_color = self.cmap.map_value_to_color(*v, fill_value); if None == mapped_color { continue; } let mapped_ring = cms.ring_map(&cell).unwrap(); let mut path = Path::new(); let mut points = mapped_ring.points(); let first_point = points.next().unwrap(); path.move_to(first_point.x(), first_point.y()); for point in points { path.line_to(point.x(), point.y()); } path.close(); canvas.fill_path(&path, &Paint::color(mapped_color.unwrap())); } } } } impl DataRenderer for GridFieldRenderer where T: Num + NumOps + PartialOrd + Copy + Clone + FromPrimitive + AsPrimitive, CMAP: ColorMapper, { type Data = Radar2d; fn render( &self, canvas: &mut Canvas, mut cms: &CMS, data: &Self::Data, size: (f32, f32), ) -> Target { let (w, h) = size; let new_img = canvas .create_image_empty(w as usize, h as usize, Rgba8, ImageFlags::empty()) .expect("Can't Create Image"); canvas.image_size(new_img).unwrap(); canvas.set_render_target(RenderTarget::Image(new_img)); let _data = data.data.view(); let (_dim1, _dim2) = meshgrid(data.dim1.view(), data.dim2.view()); let lat_start = data.dim2.view().first().unwrap().clone(); let lat_end = data.dim2.view().last().unwrap().clone(); let lon_start = data.dim1.view().first().unwrap().clone(); let lon_end = data.dim1.view().last().unwrap().clone(); cms.set_lat_range(lat_start..lat_end); cms.set_lon_range(lon_start..lon_end); self.draw_2d( canvas, &cms, _data, (_dim1.view(), _dim2.view()), (w, h), data.fill_value, ); canvas.flush(); let mut pixels: Vec = vec![0; w as usize * h as usize * 4]; unsafe { gl::ReadPixels( 0, 0, w as i32, h as i32, gl::RGBA, gl::UNSIGNED_BYTE, pixels.as_mut_ptr() as *mut GLvoid, ); debug_assert_eq!(gl::GetError(), gl::NO_ERROR); } let img: ImageBuffer, Vec> = ImageBuffer::from_raw(w as u32, h as u32, pixels) .expect("Failed to create ImageBuffer"); let thumbnail = resize(&img, 500, 500, image::imageops::FilterType::Lanczos3); let mut thumb_buffer = Cursor::new(Vec::new()); img.write_to(&mut thumb_buffer, image::ImageOutputFormat::Png) .expect("Failed to write PNG buffer"); let thumb_data = thumb_buffer.into_inner(); let thumbnail_tex = gtk::gdk::Texture::from_bytes(>k::glib::Bytes::from(&thumb_data)).unwrap(); // 将 ImageBuffer 编码为 PNG let mut png_buffer = Cursor::new(Vec::new()); img.write_to(&mut png_buffer, image::ImageOutputFormat::Bmp) .expect("Failed to write PNG buffer"); let png_data = png_buffer.into_inner(); let d1_start = (data.dim1.view()).first().unwrap().clone(); let d1_end = (data.dim1.view()).last().unwrap().clone(); let d2_start = data.dim2.view().first().unwrap().clone(); let d2_end = data.dim2.view().last().unwrap().clone(); Target::new( TargetType::Mem(png_data), w, h, ((d1_start, d1_end).into(), (d2_start, d2_end).into()), Some(thumbnail_tex), ) } } #[derive(Debug)] pub struct GridLayerImpl where T: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, CMAP: ColorMapper, { renderer: GridFieldRenderer, data: Radar2d, } pub type DbzGridLayerImpl = GridLayerImpl, i8>; impl GridLayerImpl where T: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, CMAP: ColorMapper, { pub fn new(renderer: GridFieldRenderer, data: Radar2d) -> Self { Self { renderer, data } } } impl LayerImpl for GridLayerImpl where T: Num + NumOps + PartialOrd + Copy + Clone + Debug + Send + Sync + FromPrimitive + AsPrimitive, CMAP: ColorMapper + Debug, { fn draw( &self, canvas: &mut femtovg::Canvas, cms: &CMS, ) -> Option { let result = self .renderer .render(canvas, cms, &self.data, (3000.0, 3000.0)); return Some(result); } }