211 lines
6.7 KiB
Rust
211 lines
6.7 KiB
Rust
use std::marker::PhantomData;
|
|
|
|
use crate::{data::RadarData2d, tree::get};
|
|
|
|
use super::coords::{Coord, ScreenCoord};
|
|
use gtk::{
|
|
cairo::*,
|
|
gdk::{builders::RGBABuilder, RGBA},
|
|
};
|
|
use num_traits::{FromPrimitive, Num};
|
|
pub struct Painter<'a, T: Num, C: Coord<T>> {
|
|
width: u32,
|
|
height: u32,
|
|
context: &'a Context,
|
|
coord: C,
|
|
marker: PhantomData<T>,
|
|
}
|
|
|
|
impl<'a, T: Num + Clone, C: Coord<T>> Painter<'a, T, C> {
|
|
pub fn new(context: &'a Context, coord: C, width: u32, height: u32) -> Self {
|
|
Self {
|
|
context,
|
|
coord,
|
|
width,
|
|
height,
|
|
marker: PhantomData,
|
|
}
|
|
}
|
|
|
|
fn set_color(&self, color: &RGBA) {
|
|
self.context.set_source_rgba(
|
|
color.red() as f64,
|
|
color.green() as f64,
|
|
color.blue() as f64,
|
|
color.alpha() as f64,
|
|
);
|
|
}
|
|
|
|
fn draw_pixel(&self, point: ScreenCoord, color: &RGBA) {
|
|
self.context
|
|
.rectangle(f64::from(point.0), f64::from(point.1), 1.0, 1.0);
|
|
self.set_color(color);
|
|
|
|
self.context.fill();
|
|
}
|
|
|
|
fn draw_rect(&self, point: ScreenCoord, width: f64, height: f64, color: &RGBA, fill: bool) {
|
|
self.set_color(color);
|
|
self.set_stroke_width(1);
|
|
self.context.rectangle(point.0, point.1, width, height);
|
|
self.context.fill();
|
|
// if fill {
|
|
// self.context.fill();
|
|
// } else {
|
|
// self.context.stroke();
|
|
// }
|
|
}
|
|
|
|
fn set_stroke_width(&self, width: u32) {
|
|
self.context.set_line_width(f64::from(width));
|
|
}
|
|
|
|
fn draw_line(&self, start: ScreenCoord, end: ScreenCoord) {
|
|
self.set_color(&RGBA::BLACK);
|
|
self.set_stroke_width(1);
|
|
self.context.move_to(start.0, start.1);
|
|
self.context.line_to(end.0, end.1);
|
|
|
|
self.context.stroke();
|
|
}
|
|
|
|
fn draw_path<I: IntoIterator<Item = ScreenCoord>>(&self, path: I) {
|
|
let mut path = path.into_iter();
|
|
if let Some((x, y)) = path.next() {
|
|
self.context.move_to(x, y);
|
|
}
|
|
|
|
for (x, y) in path {
|
|
self.context.line_to(x, y);
|
|
}
|
|
self.context.stroke();
|
|
}
|
|
}
|
|
|
|
impl<'a, C: Coord<f64>> Painter<'a, f64, C> {
|
|
pub fn draw_radar_2d<T: Num + Clone + PartialEq + PartialOrd + FromPrimitive + Copy, D>(
|
|
&self,
|
|
data: &RadarData2d<T, D>,
|
|
) where
|
|
D: ndarray::Data<Elem = T> + Clone + ndarray::RawDataClone,
|
|
{
|
|
let levels: Vec<T> = vec![
|
|
T::from_i8(0).unwrap(),
|
|
T::from_i8(5).unwrap(),
|
|
T::from_i8(10).unwrap(),
|
|
T::from_i8(15).unwrap(),
|
|
T::from_i8(20).unwrap(),
|
|
T::from_i8(25).unwrap(),
|
|
T::from_i8(30).unwrap(),
|
|
T::from_i8(35).unwrap(),
|
|
T::from_i8(40).unwrap(),
|
|
T::from_i8(45).unwrap(),
|
|
T::from_i8(50).unwrap(),
|
|
T::from_i8(55).unwrap(),
|
|
T::from_i8(60).unwrap(),
|
|
T::from_i8(65).unwrap(),
|
|
];
|
|
let colors = vec![
|
|
RGBABuilder::default()
|
|
.red(0 as f32 / 255.0)
|
|
.green(172 as f32 / 255.0)
|
|
.blue(164 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(192 as f32 / 255.0)
|
|
.green(192 as f32 / 255.0)
|
|
.blue(254 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(122 as f32 / 255.0)
|
|
.green(114 as f32 / 255.0)
|
|
.blue(238 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(30 as f32 / 255.0)
|
|
.green(38 as f32 / 255.0)
|
|
.blue(208 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(166 as f32 / 255.0)
|
|
.green(252 as f32 / 255.0)
|
|
.blue(168 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(0 as f32 / 255.0)
|
|
.green(234 as f32 / 255.0)
|
|
.blue(0 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(16 as f32 / 255.0)
|
|
.green(146 as f32 / 255.0)
|
|
.blue(26 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(252 as f32 / 255.0)
|
|
.green(244 as f32 / 255.0)
|
|
.blue(100 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(200 as f32 / 255.0)
|
|
.green(200 as f32 / 255.0)
|
|
.blue(2 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(140 as f32 / 255.0)
|
|
.green(140 as f32 / 255.0)
|
|
.blue(0 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(254 as f32 / 255.0)
|
|
.green(172 as f32 / 255.0)
|
|
.blue(172 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(254 as f32 / 255.0)
|
|
.green(100 as f32 / 255.0)
|
|
.blue(92 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(238 as f32 / 255.0)
|
|
.green(2 as f32 / 255.0)
|
|
.blue(48 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(212 as f32 / 255.0)
|
|
.green(142 as f32 / 255.0)
|
|
.blue(254 as f32 / 255.0)
|
|
.build(),
|
|
RGBABuilder::default()
|
|
.red(170 as f32 / 255.0)
|
|
.green(36 as f32 / 255.0)
|
|
.blue(250 as f32 / 255.0)
|
|
.build(),
|
|
];
|
|
|
|
let mut polygons: Vec<(shapefile::Polygon, _)> =
|
|
shapefile::read_as::<_, shapefile::Polygon, shapefile::dbase::Record>(
|
|
"/Users/ruomu/china/省界_region.shp",
|
|
)
|
|
.unwrap();
|
|
|
|
// for (polygon, _) in polygons.into_iter() {
|
|
// let x_range = polygon.bbox().x_range();
|
|
// let y_range = polygon.bbox().y_range();
|
|
|
|
// let lon_range = self.coord.dim1_range();
|
|
// let lat_range = self.coord.dim2_range();
|
|
// }
|
|
data.data.outer_iter().enumerate().for_each(|(r_num, row)| {
|
|
row.iter().enumerate().for_each(|(c_num, v)| {
|
|
let point = self.coord.map(data.dim1[c_num], data.dim2[r_num]);
|
|
if *v > T::from_i8(-125).unwrap() {
|
|
let color = get(&levels, &colors, *v);
|
|
// self.draw_pixel(point, &color);
|
|
self.draw_rect(point, 1.5, 1.5, &color, true);
|
|
}
|
|
})
|
|
});
|
|
}
|
|
}
|