diff --git a/.gitignore b/.gitignore index 88b0f28..ae0fd69 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ */*.litematic */*.csv */*.txt +*/*.gv diff --git a/Cargo.lock b/Cargo.lock index 110453b..0b4aff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,7 +311,7 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "voxelmap" -version = "0.2.0" +version = "0.3.0" dependencies = [ "clap", "lodepng", diff --git a/Cargo.toml b/Cargo.toml index 822f5c7..ef2e7cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "voxelmap" -version = "0.2.0" +version = "0.3.0" authors = ["raffitz "] edition = "2018" description = "Converts mathematical descriptions of objects to voxel maps" diff --git a/src/astree.rs b/src/astree.rs index 2b849b9..b57aca5 100644 --- a/src/astree.rs +++ b/src/astree.rs @@ -1,5 +1,6 @@ use crate::error::Error; use std::collections::{HashMap, HashSet}; +use std::io::Write; #[derive(Debug, PartialEq)] pub enum FunctionType { @@ -59,6 +60,35 @@ impl FunctionData { FunctionType::Neg => Ok(-value), } } + + pub fn graph(&self, output: &mut impl Write, id: usize) -> Result { + let label = match self.kind { + FunctionType::Sin => "sin", + FunctionType::Cos => "cos", + FunctionType::Tan => "tan", + FunctionType::Sec => "sec", + FunctionType::Csc => "csc", + FunctionType::Cot => "cot", + FunctionType::Asin => "asin", + FunctionType::Acos => "acos", + FunctionType::Atan => "atan", + FunctionType::Sign => "sign", + FunctionType::Abs => "abs", + FunctionType::Sqrt => "sqrt", + FunctionType::Exp => "exp", + FunctionType::Ln => "ln", + FunctionType::Log => "log_10", + FunctionType::Neg => "-", + }; + writeln!( + output, + "\tnode{} [label=\"{}\",shape=trapezium];", + id, label + )?; + let max_id = self.arg.graph(output, id + 1)?; + writeln!(output, "\tnode{} -> node{};", id, max_id)?; + Ok(max_id) + } } #[derive(Debug)] @@ -92,6 +122,24 @@ impl OperationData { _ => Err(Error::UnrecognisedBinaryOperator), } } + + pub fn graph(&self, output: &mut impl Write, id: usize) -> Result { + writeln!( + output, + "\tnode{} [label=\"{}\",shape=invtriangle];", + id, self.kind + )?; + let new_id = self.left.graph(output, id + 1)?; + let max_id = self.right.graph(output, new_id + 1)?; + writeln!(output, "\tnode{} -> node{} [label=\"left\"];", id, id + 1)?; + writeln!( + output, + "\tnode{} -> node{} [label=\"right\"];", + id, + new_id + 1 + )?; + Ok(max_id) + } } #[derive(Debug)] @@ -150,6 +198,25 @@ impl Expression { } } + pub fn graph(&self, output: &mut impl Write, id: usize) -> Result { + match self { + Expression::Float(f) => { + writeln!(output, "\tnode{} [label=\"{}\",shape=oval];", id, f)?; + Ok(id) + } + Expression::Function(f) => f.graph(output, id), + Expression::Operation(o) => o.graph(output, id), + Expression::Var(c) => { + writeln!(output, "\tnode{} [label=\"{}\",shape=egg];", id, c)?; + Ok(id) + } + Expression::Ident(s) => { + writeln!(output, "\tnode{} [label=\"{}\",shape=cds];", id, s)?; + Ok(id) + } + } + } + pub fn var_dependencies( &self, idents: &Option<&HashMap>, @@ -251,6 +318,24 @@ impl Condition { _ => Err(Error::UnrecognisedCondition), } } + + pub fn graph(&self, output: &mut impl Write, id: usize) -> Result { + writeln!( + output, + "\tnode{} [label=\"{}\",shape=square];", + id, self.kind + )?; + let new_id = self.left.graph(output, id + 1)?; + let max_id = self.right.graph(output, new_id + 1)?; + writeln!(output, "\tnode{} -> node{} [label=\"left\"];", id, id + 1)?; + writeln!( + output, + "\tnode{} -> node{} [label=\"right\"];", + id, + new_id + 1 + )?; + Ok(max_id) + } } #[derive(Debug)] @@ -283,6 +368,24 @@ impl JunctionData { _ => Err(Error::UnrecognisedJunction), } } + + pub fn graph(&self, output: &mut impl Write, id: usize) -> Result { + writeln!( + output, + "\tnode{} [label=\"{}\",shape=hexagon];", + id, self.kind + )?; + let new_id = self.left.graph(output, id + 1)?; + let max_id = self.right.graph(output, new_id + 1)?; + writeln!(output, "\tnode{} -> node{} [label=\"left\"];", id, id + 1)?; + writeln!( + output, + "\tnode{} -> node{} [label=\"right\"];", + id, + new_id + 1 + )?; + Ok(max_id) + } } #[derive(Debug)] @@ -311,4 +414,11 @@ impl Junction { Junction::Singleton(cond) => cond.eval(idents, vars), } } + + pub fn graph(&self, output: &mut impl Write, id: usize) -> Result { + match self { + Junction::Meta(meta) => meta.graph(output, id), + Junction::Singleton(cond) => cond.graph(output, id), + } + } } diff --git a/src/main.rs b/src/main.rs index 55a5ceb..18a334c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -301,6 +301,14 @@ fn main() -> Result<(), error::Error> { .takes_value(false) .multiple(false), ) + .arg( + Arg::with_name("graph") + .short("g") + .long("graph") + .help("Output graph of internal state") + .takes_value(false) + .multiple(false), + ) .arg( Arg::with_name("test") .short("t") @@ -342,6 +350,7 @@ fn main() -> Result<(), error::Error> { let offset = matches.is_present("offset"); let debug = matches.is_present("debug"); + let graph = matches.is_present("graph"); let test = matches.is_present("test"); let output_folder = if test { @@ -426,6 +435,35 @@ fn main() -> Result<(), error::Error> { }?; let idents = assigns.unwrap_or_default(); + + // Print graph + if graph { + let mut gv_file = fs::File::create(format! {"{}/state.gv",output_folder})?; + writeln!( + gv_file, + "/* Graph file generated from {} v{}, by {} */\n\n", + crate_name!(), + crate_version!(), + crate_authors!() + )?; + writeln!(gv_file, "digraph State {{")?; + // Print main condition + let tree_nodes = tree.graph(&mut gv_file, 1)?; + // Print ident definitions + let mut max_node = tree_nodes; + for (label, expression) in &idents { + writeln!( + gv_file, + "\tnode{} [label=\"{}\",shape=cds];", + max_node + 1, + label + )?; + writeln!(gv_file, "\tnode{} -> node{};", max_node + 1, max_node + 2)?; + max_node = expression.graph(&mut gv_file, max_node + 2)?; + } + writeln!(gv_file, "}}")?; + } + let ident_arg = Some(&idents); let mut min_x: Option = None; let mut max_x: Option = None;