234 lines
7.0 KiB
Rust
234 lines
7.0 KiB
Rust
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<CMAP, T>
|
|
where
|
|
T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64>,
|
|
CMAP: ColorMapper<T>,
|
|
{
|
|
cmap: CMAP,
|
|
value_phantom: PhantomData<T>,
|
|
}
|
|
|
|
impl<T: NumOps + PartialOrd + Copy + FromPrimitive + AsPrimitive<f64>, CMAP: ColorMapper<T>>
|
|
GridFieldRenderer<CMAP, T>
|
|
{
|
|
pub fn new(cmap: CMAP) -> Self {
|
|
Self {
|
|
cmap,
|
|
value_phantom: PhantomData,
|
|
}
|
|
}
|
|
fn draw_2d(
|
|
&self,
|
|
canvas: &mut femtovg::Canvas<femtovg::renderer::OpenGl>,
|
|
cms: &CMS,
|
|
data: ArrayView2<T>,
|
|
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
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<T, CMAP> DataRenderer for GridFieldRenderer<CMAP, T>
|
|
where
|
|
T: Num + NumOps + PartialOrd + Copy + Clone + FromPrimitive + AsPrimitive<f64>,
|
|
CMAP: ColorMapper<T>,
|
|
{
|
|
type Data = Radar2d<T>;
|
|
|
|
fn render(
|
|
&self,
|
|
canvas: &mut Canvas<OpenGl>,
|
|
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<u8> = 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<Rgba<u8>, Vec<u8>> = 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<CMAP, T>
|
|
where
|
|
T: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
|
CMAP: ColorMapper<T>,
|
|
{
|
|
renderer: GridFieldRenderer<CMAP, T>,
|
|
data: Radar2d<T>,
|
|
}
|
|
|
|
pub type DbzGridLayerImpl = GridLayerImpl<BoundaryNorm<i8>, i8>;
|
|
|
|
impl<CMAP, T> GridLayerImpl<CMAP, T>
|
|
where
|
|
T: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
|
CMAP: ColorMapper<T>,
|
|
{
|
|
pub fn new(renderer: GridFieldRenderer<CMAP, T>, data: Radar2d<T>) -> Self {
|
|
Self { renderer, data }
|
|
}
|
|
}
|
|
|
|
impl<CMAP, T> LayerImpl for GridLayerImpl<CMAP, T>
|
|
where
|
|
T: Num
|
|
+ NumOps
|
|
+ PartialOrd
|
|
+ Copy
|
|
+ Clone
|
|
+ Debug
|
|
+ Send
|
|
+ Sync
|
|
+ FromPrimitive
|
|
+ AsPrimitive<f64>,
|
|
CMAP: ColorMapper<T> + Debug,
|
|
{
|
|
fn draw(
|
|
&self,
|
|
canvas: &mut femtovg::Canvas<femtovg::renderer::OpenGl>,
|
|
cms: &CMS,
|
|
) -> Option<Target> {
|
|
let result = self
|
|
.renderer
|
|
.render(canvas, cms, &self.data, (3000.0, 3000.0));
|
|
return Some(result);
|
|
}
|
|
}
|