major change
This commit is contained in:
parent
f6753f2af9
commit
1652209386
200
src/graph.rs
200
src/graph.rs
|
|
@ -1,10 +1,12 @@
|
|||
//! This part do manage most of work realted to drawing graph
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::DrawingArea;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// A single line
|
||||
pub struct Line {
|
||||
pub points: Vec<(f64,f64)>,
|
||||
pub color: (f64, f64, f64)
|
||||
|
|
@ -18,45 +20,30 @@ impl Line {
|
|||
}
|
||||
}
|
||||
}
|
||||
/// Tools to draw Graph
|
||||
pub struct Graph {
|
||||
pub area: DrawingArea,
|
||||
pub scale_x_start: f64,
|
||||
pub scale_x_size: f64,
|
||||
pub scale_y_start: f64,
|
||||
pub scale_y_size: f64,
|
||||
pub draw_patch: bool,
|
||||
pub draw_baarik_box: bool,
|
||||
pub draw_box: bool,
|
||||
pub auto_adjust_y: bool,
|
||||
pub scale_x_start: f64, // start of x on pankti
|
||||
pub scale_x_size: f64, // size of pankti to show
|
||||
pub scale_y_start: f64, // start of y on stambh
|
||||
pub scale_y_size: f64, // size of stambh to show
|
||||
pub draw_patch: bool, // enable to draw circle spot on line
|
||||
pub draw_box: bool, // enable to show boxes linke graph paper
|
||||
pub draw_baarik_box: bool, // enable to show baarik(similar meaning to smaller) linke graph paper
|
||||
pub auto_adjust_y: bool, // enable to automatically adjust y axis
|
||||
pub lines: HashMap<String, Line>,
|
||||
pub pankti_sankya: f64
|
||||
pub pankti_sankya: f64 // use used while adding to point in lines to see last count of graphable input
|
||||
}
|
||||
|
||||
impl Graph {
|
||||
fn draw_boxes(ctx: &cairo::Context, area_width: f64, area_height: f64, src_x: f64, src_y: f64, cell_size: f64, color: f64) {
|
||||
ctx.set_source_rgb(color, color, color);
|
||||
ctx.set_line_width(1.0);
|
||||
for x in 1..math::round::ceil(area_width/cell_size, 0) as i32 {
|
||||
let xi = x as f64 * cell_size + src_x;
|
||||
ctx.move_to(xi, 0.0);
|
||||
ctx.line_to(xi, area_height - src_y);
|
||||
}
|
||||
for y in 1..math::round::ceil(area_height/cell_size, 0) as i32 {
|
||||
let yi = area_height - y as f64 * cell_size - src_y;
|
||||
ctx.move_to(src_x, yi);
|
||||
ctx.line_to(area_width, yi);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
pub fn new(area: DrawingArea,
|
||||
scale_x_start: f64,
|
||||
scale_x_size: f64,
|
||||
scale_y_start: f64,
|
||||
scale_y_size: f64,
|
||||
draw_patch: bool,
|
||||
draw_baarik_box: bool,
|
||||
draw_box: bool,
|
||||
draw_baarik_box: bool,
|
||||
auto_adjust_y: bool,
|
||||
lines: HashMap<String, Line>,
|
||||
pankti_sankya: f64) -> Rc<RefCell<Self>> {
|
||||
|
|
@ -68,8 +55,8 @@ impl Graph {
|
|||
scale_y_start,
|
||||
scale_y_size,
|
||||
draw_patch,
|
||||
draw_baarik_box: draw_baarik_box,
|
||||
draw_box,
|
||||
draw_baarik_box,
|
||||
auto_adjust_y,
|
||||
lines,
|
||||
pankti_sankya
|
||||
|
|
@ -84,6 +71,44 @@ impl Graph {
|
|||
graph
|
||||
}
|
||||
|
||||
/// used to draw box and baarik box
|
||||
fn draw_boxes(ctx: &cairo::Context, area_width: f64, area_height: f64, src_x: f64, cell_size: f64, color: f64) {
|
||||
ctx.set_source_rgb(color, color, color);
|
||||
ctx.set_line_width(1.0);
|
||||
// lines parallel to stambh
|
||||
for i in 1..math::round::ceil(area_width/cell_size, 0) as i32 {
|
||||
let xi = i as f64 * cell_size + src_x;
|
||||
ctx.move_to(xi, 0.0);
|
||||
ctx.line_to(xi, area_height);
|
||||
}
|
||||
// lines parallel to pankti
|
||||
for i in 1..math::round::ceil(area_height/cell_size, 0) as i32 {
|
||||
let yi = area_height - i as f64 * cell_size;
|
||||
ctx.move_to(src_x, yi);
|
||||
ctx.line_to(area_width + src_x, yi);
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
/// transform point to show on graph
|
||||
fn transform_on_graph(
|
||||
p_start: f64,
|
||||
s_start: f64,
|
||||
p: f64,
|
||||
s: f64,
|
||||
aa_dumm_pankti: f64,
|
||||
aa_dumm_stambh: f64,
|
||||
scale_x_size: f64,
|
||||
scale_y_size: f64,
|
||||
height: f64,
|
||||
stambh_scale_width: f64) -> (f64, f64){
|
||||
(
|
||||
((p - p_start) * aa_dumm_pankti)/scale_x_size + stambh_scale_width,
|
||||
height - ((s - s_start) * aa_dumm_stambh) / scale_y_size
|
||||
)
|
||||
}
|
||||
|
||||
/// callback of drawing area to draw graph
|
||||
fn draw(area: >k::DrawingArea,
|
||||
ctx: &cairo::Context,
|
||||
graph: &Rc<RefCell<Graph>>) {
|
||||
|
|
@ -93,94 +118,139 @@ impl Graph {
|
|||
ctx.set_source_rgb(0.1, 0.5, 0.5);
|
||||
ctx.paint();
|
||||
|
||||
let width = area.get_allocated_width() as f64;
|
||||
let height = area.get_allocated_height() as f64;
|
||||
let pankti_scale_height = 50.0;
|
||||
let stambh_scale_width = 60.0;
|
||||
let width = area.get_allocated_width() as f64 - stambh_scale_width;
|
||||
let height = area.get_allocated_height() as f64 - pankti_scale_height;
|
||||
|
||||
let manjusa_maap = 50.0;
|
||||
|
||||
let rekha_sankhya_pankti = math::round::floor(width / manjusa_maap, 0);
|
||||
let rekha_sankhya_stambh = math::round::floor(height / manjusa_maap, 0);
|
||||
|
||||
let aa_dumm_pankti = rekha_sankhya_pankti * manjusa_maap;
|
||||
let aa_dumm_stambh = rekha_sankhya_stambh * manjusa_maap;
|
||||
|
||||
let anupat_pankti = (manjusa_maap * graph.scale_x_size) / aa_dumm_pankti;
|
||||
let anupat_stambh = (manjusa_maap * graph.scale_y_size) / aa_dumm_stambh;
|
||||
|
||||
// drawing boxes to show area as graph paper
|
||||
if graph.draw_box {
|
||||
if graph.draw_baarik_box {
|
||||
Graph::draw_boxes(ctx, width, height, 40.0, 20.0, 5.0, 0.3);
|
||||
Graph::draw_boxes(ctx, width, height, stambh_scale_width, 5.0, 0.3);
|
||||
}
|
||||
Graph::draw_boxes(ctx, width, height, stambh_scale_width, 50.0, 0.1);
|
||||
}
|
||||
|
||||
Graph::draw_boxes(ctx, width, height, 40.0, 20.0, 50.0, 0.1);
|
||||
}
|
||||
|
||||
let cell_size = 50.0;
|
||||
|
||||
let v_bars = math::round::ceil(width/cell_size, 0) as i32;
|
||||
let h_bars= math::round::ceil(height/cell_size, 0) as i32;
|
||||
|
||||
let h_scale = (graph.scale_x_size)/(v_bars - 1) as f64; // ms
|
||||
let v_scale = (graph.scale_y_size)/(h_bars - 1) as f64; // ms
|
||||
|
||||
// Drawing point and line on graph area
|
||||
ctx.set_line_width(2.0);
|
||||
ctx.set_line_cap(cairo::LineCap::Round);
|
||||
let draw_patch = graph.draw_patch;
|
||||
for (_,line) in graph.lines.iter() {
|
||||
for p in line.points.iter().enumerate() {
|
||||
let xp = if p.0 < line.points.len() - 1 {
|
||||
line.points[p.0 + 1]
|
||||
for (i, (p,s)) in line.points.iter().enumerate() {
|
||||
// check if point is last poin on line
|
||||
let (p_dumm, s_dumm) = if i < line.points.len() - 1 {
|
||||
line.points[i + 1]
|
||||
} else {
|
||||
line.points[p.0]
|
||||
line.points[i]
|
||||
};
|
||||
|
||||
let bindu_t = Graph::transform_on_graph(
|
||||
graph.scale_x_start,
|
||||
graph.scale_y_start,
|
||||
*p,
|
||||
*s,
|
||||
aa_dumm_pankti,
|
||||
aa_dumm_stambh,
|
||||
graph.scale_x_size,
|
||||
graph.scale_y_size,
|
||||
height,
|
||||
stambh_scale_width,
|
||||
);
|
||||
|
||||
let bindu_dumm_t = Graph::transform_on_graph(
|
||||
graph.scale_x_start,
|
||||
graph.scale_y_start,
|
||||
p_dumm,
|
||||
s_dumm,
|
||||
aa_dumm_pankti,
|
||||
aa_dumm_stambh,
|
||||
graph.scale_x_size,
|
||||
graph.scale_y_size,
|
||||
height,
|
||||
stambh_scale_width,
|
||||
);
|
||||
|
||||
ctx.set_source_rgb(line.color.0, line.color.1, line.color.2);
|
||||
ctx.move_to(((cell_size as f64)*(xp.0 - graph.scale_x_start))/h_scale + 40.0, height - ((cell_size as f64)*(xp.1 - graph.scale_y_start))/v_scale - 20.0);
|
||||
ctx.line_to(((cell_size as f64)*(p.1.0 - graph.scale_x_start))/h_scale + 40.0, height - ((cell_size as f64)*(p.1.1 - graph.scale_y_start))/v_scale - 20.0);
|
||||
ctx.move_to(bindu_dumm_t.0, bindu_dumm_t.1);
|
||||
ctx.line_to(bindu_t.0, bindu_t.1);
|
||||
ctx.stroke();
|
||||
|
||||
// draw circle over point
|
||||
if draw_patch {
|
||||
ctx.set_source_rgb(0.0, 0.0, 1.0);
|
||||
ctx.arc(((cell_size as f64)*(p.1.0 - graph.scale_x_start))/h_scale + 40.0, height - ((cell_size as f64)*(p.1.1 - graph.scale_y_start))/v_scale - 20.0, 5.0, 0.0, std::f64::consts::PI * 2.0);
|
||||
ctx.arc(bindu_dumm_t.0, bindu_dumm_t.1,
|
||||
5.0, 0.0, std::f64::consts::PI * 2.0);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw darker recragle over scales
|
||||
ctx.set_source_rgb(0.1, 0.4, 0.4);
|
||||
ctx.rectangle(0.0, 0.0, 40.0, height);
|
||||
ctx.rectangle(0.0, height - 20.0, width, 20.0);
|
||||
ctx.rectangle(0.0, 0.0, stambh_scale_width, height + pankti_scale_height);
|
||||
ctx.rectangle(stambh_scale_width, height, width, pankti_scale_height);
|
||||
ctx.fill();
|
||||
|
||||
ctx.set_source_rgb(1.0, 1.0, 1.0);
|
||||
for x in 0..v_bars {
|
||||
let text = math::round::floor(x as f64 * h_scale + graph.scale_x_start, 1).to_string();
|
||||
// write numbers on pankti scale
|
||||
for i in 0..(rekha_sankhya_pankti as i32 + 1) {
|
||||
let text = math::round::floor(i as f64 * anupat_pankti + graph.scale_x_start, 4).to_string();
|
||||
let f = ctx.text_extents(&text);
|
||||
ctx.move_to(40.0 + x as f64 * cell_size - f.width, height - 10.0);
|
||||
ctx.move_to(i as f64 * manjusa_maap - f.width + stambh_scale_width + f.height / 0.866, height + f.width * 0.5 + f.height);
|
||||
ctx.save();
|
||||
ctx.rotate(std::f64::consts::PI / -6.0);
|
||||
ctx.show_text(&text);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
for y in (0..h_bars).rev() {
|
||||
let text = math::round::floor(y as f64 * v_scale + graph.scale_y_start, 1).to_string();
|
||||
// write numbers on stambh scale
|
||||
for i in (0..aa_dumm_stambh as i32 + 1).rev() {
|
||||
let text = math::round::floor(i as f64 * anupat_stambh + graph.scale_y_start, 4).to_string();
|
||||
let f = ctx.text_extents(&text);
|
||||
ctx.move_to(40.0 - f.width, height - y as f64 * cell_size - f.height - 15.0);
|
||||
ctx.move_to(stambh_scale_width - f.width + f.height / 1.732, height - i as f64 * manjusa_maap + f.width * 0.5);
|
||||
ctx.save();
|
||||
ctx.rotate(std::f64::consts::PI / -6.0);
|
||||
ctx.show_text(&text);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjust stambh and pankti as needed , trim lines and redraws
|
||||
pub fn redraw(&mut self) {
|
||||
let (mx_x, mi_x, mx_y, mi_y) = self.get_extremes();
|
||||
|
||||
// stambh
|
||||
if self.auto_adjust_y {
|
||||
let spread = (mx_y - mi_y).abs();
|
||||
|
||||
self.scale_y_start = mi_y - spread * 0.1;
|
||||
self.scale_y_size = spread * 1.2;
|
||||
}
|
||||
|
||||
// pankti
|
||||
let spread = (mx_x - mi_x).abs();
|
||||
|
||||
if spread < self.scale_x_size {
|
||||
self.scale_x_start = mi_x;
|
||||
} else {
|
||||
self.scale_x_start = mx_x - self.scale_x_size;
|
||||
}
|
||||
|
||||
self.trim_lines();
|
||||
self.area.queue_draw();
|
||||
self.trim_lines(); // trim
|
||||
self.area.queue_draw(); // redraw
|
||||
}
|
||||
|
||||
/// find minimun and maximum value from all lines
|
||||
pub fn get_extremes(&self) -> (f64, f64, f64, f64){
|
||||
// trick to avoid no lines
|
||||
if self.lines.len() == 0 {
|
||||
return (0.0,0.0,0.0,0.0);
|
||||
}
|
||||
|
|
@ -199,6 +269,10 @@ impl Graph {
|
|||
continue;
|
||||
}
|
||||
|
||||
// keeping these in here is a good idea than picking line[0].point[0]
|
||||
// because consider if 0th line have no points and 1st too than that fails
|
||||
// and also if we keep 0 as default value to start then a graph with
|
||||
// 100 to 200 will have 0 as minimum
|
||||
if let None = mx_x {
|
||||
mx_x = Some(line.points[0].0);
|
||||
}
|
||||
|
|
@ -226,6 +300,8 @@ impl Graph {
|
|||
(mx_x.unwrap(), mi_x.unwrap(), mx_y.unwrap(), mi_y.unwrap())
|
||||
}
|
||||
|
||||
// tims line form left side of line. Why left?? to avoid wasting time in ponits in range
|
||||
// it skips i point out of screen to keep a non terminating line experience
|
||||
pub fn trim_lines(&mut self) {
|
||||
for (_, line) in self.lines.iter_mut() {
|
||||
let mut i = 0;
|
||||
|
|
|
|||
52
src/lib.rs
52
src/lib.rs
|
|
@ -12,8 +12,9 @@ use std::io::BufReader;
|
|||
|
||||
use graph::Graph;
|
||||
|
||||
pub enum Status {
|
||||
JAGRIT, SAYAN, AVRODTIH, PARIVARTIT, NIKAS
|
||||
/// Status of Serial reading
|
||||
enum Status {
|
||||
JAGRIT, SAYAN, AVRODTIH, PARIVARTIT
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
|
|
@ -22,6 +23,7 @@ pub struct Config {
|
|||
port: String
|
||||
}
|
||||
|
||||
//
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config {
|
||||
|
|
@ -50,7 +52,7 @@ pub fn build_ui(app: >k::Application, config: Arc::<Mutex::<Config>>) {
|
|||
0.0, 100.0,
|
||||
0.0, 100.0,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
HashMap::new(),
|
||||
|
|
@ -72,6 +74,10 @@ pub fn build_ui(app: >k::Application, config: Arc::<Mutex::<Config>>) {
|
|||
let about_menu = builder.get_object::<gtk::MenuItem>("about_menu").expect("Resource file missing!");
|
||||
let about = builder.get_object::<gtk::AboutDialog>("about").expect("Resource file missing!");
|
||||
|
||||
about.connect_close(|a| {
|
||||
a.hide();
|
||||
});
|
||||
|
||||
about_menu.connect_activate(move |_|{
|
||||
about.show_all();
|
||||
});
|
||||
|
|
@ -155,6 +161,7 @@ pub fn build_ui(app: >k::Application, config: Arc::<Mutex::<Config>>) {
|
|||
|
||||
let tmp_graph = Rc::clone(&graph);
|
||||
draw_box.connect_clicked(move |btn| {
|
||||
draw_baarik_box.set_sensitive(btn.get_active());
|
||||
let mut tmp_graph = tmp_graph.borrow_mut();
|
||||
tmp_graph.draw_box = btn.get_active();
|
||||
tmp_graph.redraw();
|
||||
|
|
@ -311,21 +318,6 @@ pub fn build_ui(app: >k::Application, config: Arc::<Mutex::<Config>>) {
|
|||
}
|
||||
glib::Continue(true)
|
||||
});
|
||||
|
||||
// Time ke hisab se pankti ko aage bhadhay
|
||||
// let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
// glib::timeout_add(300, move || {
|
||||
// sender.send(()).unwrap();
|
||||
// glib::Continue(true)
|
||||
// });
|
||||
|
||||
// let tmp_graph = Rc::clone(&graph);
|
||||
// receiver.attach(None, move |_| {
|
||||
// // println!("{:?}", tmp_graph.borrow_mut().lines[0].points);
|
||||
// tmp_graph.borrow_mut().scale_x_start += 1.0;
|
||||
// tmp_graph.borrow_mut().redraw();
|
||||
// glib::Continue(true)
|
||||
// });
|
||||
}
|
||||
|
||||
fn serial_thread_work(
|
||||
|
|
@ -333,6 +325,7 @@ fn serial_thread_work(
|
|||
bufread: &mut Option<BufReader<Box<dyn serialport::SerialPort>>>,
|
||||
sender: &glib::Sender<MessageSerialThread>,
|
||||
buf: &mut String) {
|
||||
let mut do_sleep = false;
|
||||
match config.lock() {
|
||||
Ok(mut config) => {
|
||||
match config.status {
|
||||
|
|
@ -348,7 +341,6 @@ fn serial_thread_work(
|
|||
}
|
||||
}
|
||||
},
|
||||
Status::NIKAS => {},
|
||||
Status::PARIVARTIT => {
|
||||
let p = match serialport::new(&config.port, config.bondrate).open() {
|
||||
Ok(p) => p,
|
||||
|
|
@ -360,18 +352,29 @@ fn serial_thread_work(
|
|||
*bufread = Some(BufReader::new(p));
|
||||
config.status = Status::JAGRIT;
|
||||
},
|
||||
Status::SAYAN => {}
|
||||
Status::SAYAN => {
|
||||
do_sleep = true;
|
||||
}
|
||||
}
|
||||
|
||||
}, Err(_) => {
|
||||
sender.send(MessageSerialThread::Status("Faild prepare for communication!".to_owned())).unwrap();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Hack for smooth performance
|
||||
if do_sleep {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
} else {
|
||||
std::thread::sleep(std::time::Duration::from_nanos(1));
|
||||
}
|
||||
}
|
||||
|
||||
fn receiver_for_msg(text: String, graph: &Rc<RefCell<Graph>>, full_log: >k::CheckButton, log_area: >k::TextView) {
|
||||
if text.starts_with("#") {
|
||||
for text in text.lines() {
|
||||
if text.len() == 0 {
|
||||
return;
|
||||
} else if text.starts_with("#") {
|
||||
graph.borrow_mut().pankti_sankya += 1.0;
|
||||
for (index, line) in text[1..].split(" ").enumerate() {
|
||||
let part = line.split("=");
|
||||
|
|
@ -424,17 +427,18 @@ fn receiver_for_msg(text: String, graph: &Rc<RefCell<Graph>>, full_log: >k::Ch
|
|||
if full_log.get_active(){
|
||||
let buf = log_area.get_buffer()
|
||||
.expect("Couldn't get log_area");
|
||||
buf.insert(&mut buf.get_end_iter(), &text);
|
||||
buf.insert(&mut buf.get_end_iter(), &format!("{}\n",text));
|
||||
log_area.scroll_to_iter(&mut buf.get_end_iter(), 0.4, true, 0.0, 0.0);
|
||||
log_area.queue_draw();
|
||||
}
|
||||
} else {
|
||||
let buf = log_area.get_buffer()
|
||||
.expect("Couldn't get log_area");
|
||||
buf.insert(&mut buf.get_end_iter(), &text);
|
||||
buf.insert(&mut buf.get_end_iter(), &format!("{}\n",text));
|
||||
log_area.scroll_to_iter(&mut buf.get_end_iter(), 0.4, true, 0.0, 0.0);
|
||||
log_area.queue_draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn send_text(config: &Arc<Mutex<Config>>, entry: >k::Entry, bar: >k::Statusbar) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<property name="program-name">Tarangam (तरंगम्)</property>
|
||||
<property name="comments" translatable="yes">A simple serial plotter.
|
||||
एक सरल सीरीय्ल पलौटर।</property>
|
||||
<property name="authors">Piyush Mishra</property>
|
||||
<property name="logo-icon-name">image-missing</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox">
|
||||
|
|
@ -278,6 +277,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
<property name="program-name">Tarangam (तरंगम्)</property>
|
||||
<property name="comments" translatable="yes">A simple serial plotter.
|
||||
एक सरल सीरीय्ल पलौटर।</property>
|
||||
<property name="authors">Piyush Mishra</property>
|
||||
<property name="logo-icon-name">image-missing</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox">
|
||||
|
|
@ -278,6 +277,7 @@
|
|||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw-indicator">True</property>
|
||||
</object>
|
||||
</child>
|
||||
|
|
|
|||
Loading…
Reference in New Issue