From 0a90e486c3ea6a9e101e8293de8615832ef7d883 Mon Sep 17 00:00:00 2001 From: sleptworld Date: Mon, 12 Jun 2023 19:07:17 +0800 Subject: [PATCH] drag animation 60 fps testing --- Cargo.lock | 9 ++-- Cargo.toml | 1 + src/main.rs | 67 ++++++++++++++++++------- src/painter/coords/mod.rs | 1 + src/painter/coords/wgs84.rs | 5 ++ src/painter/mod.rs | 3 +- src/painter/painter.rs | 98 +++++++++++++++++++++++-------------- 7 files changed, 122 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7a38456..2c914a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -209,6 +209,7 @@ dependencies = [ "geo-types", "glib", "glib-build-tools", + "glib-macros", "gtk4", "ndarray", "npyz", @@ -657,15 +658,15 @@ dependencies = [ [[package]] name = "glib-build-tools" -version = "0.17.10" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a65d79efe318ef2cbbbb37032b125866fd82c34ea44c816132621bbc552e716" +checksum = "8f8480c9ba9cc06aa8d5baf446037f8dc237bee127e9b62080c4db7e293d8ea0" [[package]] name = "glib-macros" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7206c5c03851ef126ea1444990e81fdd6765fb799d5bc694e4897ca01bb97f" +checksum = "eca5c79337338391f1ab8058d6698125034ce8ef31b72a442437fa6c8580de26" dependencies = [ "anyhow", "heck", diff --git a/Cargo.toml b/Cargo.toml index 9af067c..52c410f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ npyz = { version = "0.8.0", features = ["npz"] } ndarray = "0.15.6" quadtree_rs = "0.1.2" proj-sys = "0.23.1" +glib-macros = "0.17.10" [build-dependencies] diff --git a/src/main.rs b/src/main.rs index 01db824..b2aa20e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,9 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::time::Duration; + +use glib::{timeout_add, timeout_add_local}; +use glib_macros::clone; use gtk::gdk::Display; use gtk::{ gio, glib, style_context_add_provider_for_display, Application, ApplicationWindow, CssProvider, @@ -11,9 +17,10 @@ mod painter; mod render; mod tree; mod window; -use data::{CoordType, Npz, Radar2d}; -use painter::wgs84::{LatLonCoord, Mercator, Range}; -use painter::Painter; +use data::{Npz, Radar2d, RadarData2d}; +use num_traits::{FromPrimitive, Num}; +use painter::wgs84::{LatLonCoord, Mercator, ProjectionS, Range}; +use painter::{Coord, Painter}; const APP_ID: &str = "org.gtk_rs.HelloWorld2"; @@ -33,33 +40,55 @@ fn main() -> glib::ExitCode { fn build_ui(app: &Application) { // Create a window and set the title - - // let window = Window::new(app); - let window = ApplicationWindow::builder() .application(app) .title("My GTK App") .build(); let drawing_area = DrawingArea::new(); - let path = "/Users/ruomu/test2.npz"; + let path = "/home/ruomu/Desktop/test.npz"; let data = Radar2d::::load(path, Npz).unwrap(); + + let data = Rc::new(RefCell::new(data)); + let data3_clone = data.clone(); + + let projection = Mercator::new(); + let aa = Range::from(( + *data.borrow().0.dim1.first().unwrap(), + *data.borrow().0.dim1.last().unwrap(), + )); + let ab = Range::from(( + *data.borrow().0.dim2.first().unwrap(), + *data.borrow().0.dim2.last().unwrap(), + )); + let coord = LatLonCoord::new(Some(aa), Some(ab), ((0, 1000), (0, 1000)), projection); + let painter = Rc::new(RefCell::new(Painter::new(coord, 1000, 1000))); + let painter_b = painter.clone(); + let gesture = GestureDrag::new(); - // gesture.connect_drag_end(|s, x, y| { - // (&drawing_area).queue_draw(); - // }); - // drawing_area.add_controller(gesture); - drawing_area.set_draw_func(move |a, b, c, d| { - let projection = Mercator::new(); - let aa = Range::from((*data.0.dim1.first().unwrap(), *data.0.dim1.last().unwrap())); - let ab = Range::from((*data.0.dim2.first().unwrap(), *data.0.dim2.last().unwrap())); + gesture.connect_drag_update(clone!( + @strong drawing_area => move |_, x,y| { + let painter = painter.clone(); + painter.borrow_mut().set_shift(x,y); + println!("{:.2},{:.2}",x,y); + } + )); - let coord = LatLonCoord::new(Some(aa), Some(ab), ((0, c), (0, d)), projection); - let painter: Painter<'_, f64, LatLonCoord> = - Painter::new(b, coord, c as u32, c as u32); - painter.draw_radar_2d(&data.0); + drawing_area.add_controller(gesture); + + drawing_area.set_draw_func(move |a, b, c, d| { + painter_b.borrow().draw_radar_2d(b, &data3_clone.borrow().0); }); + + timeout_add_local( + Duration::from_micros(1000u64 / 20u64), + clone!(@strong drawing_area => move || { + drawing_area.queue_draw(); + Continue(true) + }), + ); + window.set_child(Some(&drawing_area)); window.set_default_width(1000); window.set_default_height(800); diff --git a/src/painter/coords/mod.rs b/src/painter/coords/mod.rs index 70fbaef..27b2d6b 100644 --- a/src/painter/coords/mod.rs +++ b/src/painter/coords/mod.rs @@ -8,4 +8,5 @@ pub trait Coord { fn dim1_range(&self) -> (T, T); fn dim2_range(&self) -> (T, T); + } diff --git a/src/painter/coords/wgs84.rs b/src/painter/coords/wgs84.rs index ccb5448..5940700 100644 --- a/src/painter/coords/wgs84.rs +++ b/src/painter/coords/wgs84.rs @@ -69,6 +69,10 @@ impl LatLonCoord { } } + pub fn set_actual(&mut self,actual: ((i32, i32), (i32, i32))) { + self.actual = (Range::from(actual.0), Range::from(actual.1)); + } + pub fn lon_range(&self) -> Range { self.pcs.lon_range } @@ -102,6 +106,7 @@ impl Coord for LatLonCoord { let v = self.lat_range(); (v.0, v.1) } + } #[derive(Clone, Debug)] diff --git a/src/painter/mod.rs b/src/painter/mod.rs index afd1733..aac3685 100644 --- a/src/painter/mod.rs +++ b/src/painter/mod.rs @@ -2,4 +2,5 @@ mod coords; mod painter; pub use painter::Painter; -pub use coords::wgs84; \ No newline at end of file +pub use coords::wgs84; +pub use coords::Coord; \ No newline at end of file diff --git a/src/painter/painter.rs b/src/painter/painter.rs index bd77f49..43d89a4 100644 --- a/src/painter/painter.rs +++ b/src/painter/painter.rs @@ -1,4 +1,8 @@ -use std::marker::PhantomData; +use std::{ + cell::{Ref, RefCell}, + marker::PhantomData, + rc::{self, Rc}, +}; use crate::{data::RadarData2d, tree::get}; @@ -8,27 +12,27 @@ use gtk::{ gdk::{builders::RGBABuilder, RGBA}, }; use num_traits::{FromPrimitive, Num}; -pub struct Painter<'a, T: Num, C: Coord> { +pub struct Painter> { width: u32, height: u32, - context: &'a Context, + shift: (f64, f64), coord: C, marker: PhantomData, } -impl<'a, T: Num + Clone, C: Coord> Painter<'a, T, C> { - pub fn new(context: &'a Context, coord: C, width: u32, height: u32) -> Self { +impl> Painter { + pub fn new(coord: C, width: u32, height: u32) -> Self { Self { - context, coord, width, height, + shift: (0f64, 0f64), marker: PhantomData, } } - fn set_color(&self, color: &RGBA) { - self.context.set_source_rgba( + fn set_color(&self, context: &Context, color: &RGBA) { + context.set_source_rgba( color.red() as f64, color.green() as f64, color.blue() as f64, @@ -36,19 +40,30 @@ impl<'a, T: Num + Clone, C: Coord> Painter<'a, T, C> { ); } - 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); + fn draw_pixel(&self, context: &Context, point: ScreenCoord, color: &RGBA) { + context.rectangle(f64::from(point.0), f64::from(point.1), 1.0, 1.0); + self.set_color(context, color); - self.context.fill(); + 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(); + pub fn set_shift(&mut self, dx: f64, dy: f64) { + self.shift = (self.shift.0 + dx, self.shift.1 + dy); + } + + fn draw_rect( + &self, + context: &Context, + point: ScreenCoord, + width: f64, + height: f64, + color: &RGBA, + fill: bool, + ) { + self.set_color(context, color); + self.set_stroke_width(context, 1); + context.rectangle(point.0, point.1, width, height); + context.fill(); // if fill { // self.context.fill(); // } else { @@ -56,35 +71,40 @@ impl<'a, T: Num + Clone, C: Coord> Painter<'a, T, C> { // } } - fn set_stroke_width(&self, width: u32) { - self.context.set_line_width(f64::from(width)); + fn translate(&self,context:&Context) { + context.translate(self.shift.0, self.shift.1); } - 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 set_stroke_width(&self, context: &Context, width: u32) { + context.set_line_width(f64::from(width)); } - fn draw_path>(&self, path: I) { + fn draw_line(&self, context: &Context, start: ScreenCoord, end: ScreenCoord) { + self.set_color(context, &RGBA::BLACK); + self.set_stroke_width(context, 1); + context.move_to(start.0, start.1); + context.line_to(end.0, end.1); + + context.stroke(); + } + + fn draw_path>(&self, context: &Context, path: I) { let mut path = path.into_iter(); if let Some((x, y)) = path.next() { - self.context.move_to(x, y); + context.move_to(x, y); } for (x, y) in path { - self.context.line_to(x, y); + context.line_to(x, y); } - self.context.stroke(); + context.stroke(); } } -impl<'a, C: Coord> Painter<'a, f64, C> { +impl> Painter { pub fn draw_radar_2d( &self, + context: &Context, data: &RadarData2d, ) where D: ndarray::Data + Clone + ndarray::RawDataClone, @@ -183,11 +203,11 @@ impl<'a, C: Coord> Painter<'a, f64, C> { .build(), ]; - let mut polygons: Vec<(shapefile::Polygon, _)> = - shapefile::read_as::<_, shapefile::Polygon, shapefile::dbase::Record>( - "/Users/ruomu/china/省界_region.shp", - ) - .unwrap(); + // 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(); @@ -196,13 +216,15 @@ impl<'a, C: Coord> Painter<'a, f64, C> { // let lon_range = self.coord.dim1_range(); // let lat_range = self.coord.dim2_range(); // } + + self.translate(context); 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); + self.draw_rect(context, point, 1.5, 1.5, &color, true); } }) });