From 53bd4a9d226e741519043352a8fd084065dae0f6 Mon Sep 17 00:00:00 2001 From: Dane Johnson Date: Wed, 4 May 2022 15:45:20 -0500 Subject: [PATCH] Begin to migrate board logic to seperate file --- src/board.rs | 116 +++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 130 ++++----------------------------------------------- 2 files changed, 124 insertions(+), 122 deletions(-) create mode 100644 src/board.rs diff --git a/src/board.rs b/src/board.rs new file mode 100644 index 0000000..2bc3bdb --- /dev/null +++ b/src/board.rs @@ -0,0 +1,116 @@ +use serde::{ Serialize, Deserialize }; +use std::collections::{ HashMap, HashSet }; + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(default)] +pub struct Node { + pub x: f32, + pub y: f32, + + pub name: String, + pub edges: HashSet, + pub labels: HashMap, +} +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(default)] +pub struct Board { + pub labels: HashMap>, + pub nodes: HashMap, +} +impl Board { + pub fn new() -> Self { + let nodes = HashMap::new(); + let labels = HashMap::new(); + Board { nodes, labels } + } + + pub fn add_node(&mut self, x: f32, y: f32, name: String) { + self.nodes.insert(self.next_id(), Node { + x, + y, + name, + edges: HashSet::new(), + labels: HashMap::new(), + }); + } + + pub fn remove_node(&mut self, id: usize) { + // We remove this node from the graph, then drop it from each + // other nodes edge. + self.nodes.remove(&id); + for node in self.nodes.values_mut() { + node.edges.remove(&id); + } + } + + pub fn nearest_node(&self, x: f32, y: f32) -> Option { + let f = |n: &Node| dist_sq((n.x, n.y), (x, y)); + let mut iter = self.nodes.iter(); + if let Some((id, node)) = iter.next() { + let mut min = *id; + let mut min_val = f(node); + for (id, node) in iter { + let val = f(node); + if val < min_val { + min = *id; + min_val = val; + } + } + Some(min) + } else { + None + } + } + + fn next_id(&self) -> usize { + for i in 0 .. { + if !self.nodes.contains_key(&i) { + return i; + } + } + unreachable!(); + } +} + +fn dist_sq((x0, y0): (f32, f32), (x1, y1): (f32, f32)) -> f32 { + (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0) +} + +use std::io; +use std::io::{ Write, Read, Cursor }; +use std::fs::File; +use std::path::Path; + +use image::io::Reader as ImageReader; +use image::{ DynamicImage }; + +pub fn write_board_to_file(board: &Board, image: Option<&DynamicImage>, path: &Path) -> io::Result<()> { + let file = File::create(path)?; + let mut ar = zip::ZipWriter::new(file); + let options = zip::write::FileOptions::default(); + + ar.start_file("graph.json", options)?; + ar.write(&serde_json::to_vec(board)?)?; + if let Some(image) = image { + ar.start_file("image.png", options)?; + let data = encode_png(image); + ar.write_all(&data)?; + ar.flush()?; + } + ar.finish()?; + Ok(()) +} + +pub fn encode_png(image: &DynamicImage) -> Vec { + let mut cursor = Cursor::new(Vec::new()); + image.write_to(&mut cursor, image::ImageOutputFormat::Png).unwrap(); + cursor.into_inner() +} + +pub fn decode_png(buf: &[u8]) -> DynamicImage { + let cursor = Cursor::new(buf); + let mut reader = ImageReader::new(cursor); + reader.set_format(image::ImageFormat::Png); + reader.decode().unwrap() +} + diff --git a/src/main.rs b/src/main.rs index c14cef7..e88dbd5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -use serde::{ Serialize, Deserialize }; - use fltk::*; use fltk::prelude::*; use fltk::enums::*; @@ -11,102 +9,19 @@ use image::{ DynamicImage }; use state::Storage; -use std::collections::{HashMap, HashSet}; - use std::sync::Mutex; -use std::io::{ Write, Read, Cursor }; use std::fs::File; +use std::io::Read; + +mod board; +use board::Board; +use board::{ encode_png, decode_png, write_board_to_file }; //////////////////// Global State //////////////////// // Don't @ me... static STATE: Storage> = Storage::new(); -//////////////////// Data Layout //////////////////// - -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(default)] -struct Node { - pub x: f32, - pub y: f32, - - pub name: String, - pub edges: HashSet, - pub labels: HashMap, -} -#[derive(Serialize, Deserialize, Debug, Default)] -#[serde(default)] -struct Board { - labels: HashMap>, - nodes: HashMap, -} -impl Board { - pub fn new() -> Self { - let nodes = HashMap::new(); - let labels = HashMap::new(); - Board { nodes, labels } - } - - pub fn new_node(&mut self, x: f32, y: f32) -> usize { - let id = self.next_id(); - self.nodes.insert(id, Node { - x, - y, - name: String::new(), - edges: HashSet::new(), - labels: HashMap::new(), - }); - id - } - - pub fn add_node(&mut self, x: f32, y: f32, name: String) { - self.nodes.insert(self.next_id(), Node { - x, - y, - name, - edges: HashSet::new(), - labels: HashMap::new(), - }); - } - - pub fn remove_node(&mut self, id: usize) { - // We remove this node from the graph, then drop it from each - // other nodes edge. - self.nodes.remove(&id); - for node in self.nodes.values_mut() { - node.edges.remove(&id); - } - } - - pub fn nearest_node(&self, x: f32, y: f32) -> Option { - let f = |n: &Node| dist_sq((n.x, n.y), (x, y)); - let mut iter = self.nodes.iter(); - if let Some((id, node)) = iter.next() { - let mut min = *id; - let mut min_val = f(node); - for (id, node) in iter { - let val = f(node); - if val < min_val { - min = *id; - min_val = val; - } - } - Some(min) - } else { - None - } - } - - fn next_id(&self) -> usize { - for i in 0 .. { - if !self.nodes.contains_key(&i) { - return i; - } - } - unreachable!(); - } -} - //////////////////// Auxilary Dialogs //////////////////// fn add_remove_labels_dialog() { let mut state = STATE.get().lock().unwrap(); @@ -226,19 +141,6 @@ mod dispatch { //////////////////// Utility Functions //////////////////// -fn encode_png(image: &DynamicImage) -> Vec { - let mut cursor = Cursor::new(Vec::new()); - image.write_to(&mut cursor, image::ImageOutputFormat::Png).unwrap(); - cursor.into_inner() -} - -fn decode_png(buf: &[u8]) -> DynamicImage { - let cursor = Cursor::new(buf); - let mut reader = ImageReader::new(cursor); - reader.set_format(image::ImageFormat::Png); - reader.decode().unwrap() -} - fn lerp(v0: f32, v1: f32, t: f32) -> f32 { v0 + t * (v1 - v0) } @@ -247,10 +149,6 @@ fn inv_lerp(v0: f32, v1: f32, a: f32) -> f32 { (a - v0) / (v1 - v0) } -fn dist_sq((x0, y0): (f32, f32), (x1, y1): (f32, f32)) -> f32 { - (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0) -} - trait CoordTransformer { fn to_coords(&self, x: i32, y: i32) -> (f32, f32); fn from_coords(&self, x: f32, y: f32) -> (i32, i32); @@ -356,23 +254,11 @@ fn main() { } }); menubar.add("File/Save As ...", Shortcut::None, menu::MenuFlag::Normal, move |_| { + let state = STATE.get().lock().unwrap(); let mut fc = dialog::NativeFileChooser::new(dialog::NativeFileChooserType::BrowseSaveFile); fc.show(); - - let file = File::create(fc.filename()).unwrap(); - let mut ar = zip::ZipWriter::new(file); - let options = zip::write::FileOptions::default(); - let state = STATE.get().lock().unwrap(); - - ar.start_file("graph.json", options).ok(); - ar.write(&serde_json::to_vec(&state.board).unwrap()).ok(); - if let Some(image) = state.image_raw.as_ref() { - ar.start_file("image.png", options).ok(); - let data = encode_png(image); - ar.write_all(&data).unwrap(); - ar.flush().unwrap(); - } - ar.finish().ok(); + let filename = fc.filename(); + write_board_to_file(&state.board, state.image_raw.as_ref(), &filename).unwrap(); }); menubar.add("Edit/Edit Nodes", Shortcut::None, menu::MenuFlag::Normal, |_| { let mut state = STATE.get().lock().unwrap();