From 137f269b4745339d02187871de373331df06bec9 Mon Sep 17 00:00:00 2001 From: Leo Le Bouter Date: Wed, 7 Oct 2020 02:22:40 +0200 Subject: [PATCH] First draft First attempt at this, we have some output that remains to be tested for correctness. --- .gitignore | 5 ++ Cargo.toml | 14 +++++ src/main.rs | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore index 62bd1a4..29a7654 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + + +#Added by cargo + +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..fc659d0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "lasy-cli" +version = "0.1.0" +authors = ["Leo Le Bouter "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = "1.0.116" +serde_json = "1.0.58" +lasy = "0.4.1" +clap = "2.33.3" +anyhow = "1.0.33" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..160f173 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,156 @@ +use std::{hash::Hash, hash::Hasher, io}; + +use anyhow::Result; +use clap::{app_from_crate, crate_authors, crate_description, crate_name, crate_version, App, Arg}; +use io::Write; +use lasy::{ + euler_graph_to_euler_circuit, interpolate_euler_circuit, point_graph_to_euler_graph, + points_to_segments, segments_to_point_graph, Blanked, InterpolationConfig, IsBlank, Lerp, + Position, Weight, +}; + +type InputArrayEntry = (f32, f32, u32); + +#[derive(Clone, Copy)] +struct Point { + x: f32, + y: f32, + color: u32, + weight: u32, +} + +impl Hash for Point { + fn hash(&self, hasher: &mut H) { + #[derive(Hash, Eq, PartialEq)] + struct HashPoint { + x: u32, + y: u32, + color: u32, + } + + impl From for HashPoint { + fn from(p: Point) -> Self { + HashPoint { + x: (p.x * i16::MAX as f32) as u32, + y: (p.y * i16::MAX as f32) as u32, + color: p.color, + } + } + } + + HashPoint::from(*self).hash(hasher); + } +} + +impl Position for Point { + fn position(&self) -> [f32; 2] { + [self.x, self.y] + } +} + +impl IsBlank for Point { + fn is_blank(&self) -> bool { + self.color == 0xffffff + } +} + +impl Blanked for Point { + fn blanked(&self) -> Self { + Self { + color: 0xffffff, + ..*self + } + } +} + +impl Weight for Point { + fn weight(&self) -> u32 { + self.weight + } +} + +impl Lerp for Point { + type Scalar = f32; + fn lerp(&self, other: &Self, amt: f32) -> Self { + let v = [self.x, self.y].lerp(&[other.x, other.y], amt); + + let (b1, g1, r1) = ( + ((self.color) & 0xff) as f32, + ((self.color >> 8) & 0xff) as f32, + ((self.color >> 16) & 0xff) as f32, + ); + + let (b2, g2, r2) = ( + ((other.color) & 0xff) as f32, + ((other.color >> 8) & 0xff) as f32, + ((other.color >> 16) & 0xff) as f32, + ); + + let [r3, g3, b3] = [r1, g1, b1].lerp(&[r2, g2, b2], amt); + + let color: u32 = ((r3 as u32) << 16) | ((g3 as u32) << 8) | b3 as u32; + + Point { + x: v[0], + y: v[1], + color, + weight: self.weight, + } + } +} + +fn optimize_line(default_weight: u32, line: &str) -> Result> { + let frame: Vec = serde_json::from_str(line)?; + + let input_points: Vec = frame + .into_iter() + .map(|(x, y, color)| Point { + x, + y, + color, + weight: default_weight, + }) + .collect(); + + let segs = points_to_segments(&input_points); + let pg = segments_to_point_graph(&input_points, segs); + let eg = point_graph_to_euler_graph(&pg); + let ec = euler_graph_to_euler_circuit(&input_points, &eg); + let output_points: Vec = interpolate_euler_circuit( + &input_points, + &ec, + &eg, + input_points.len() as u32, + &InterpolationConfig::default(), + ); + + let output_frame: Vec<_> = output_points.iter().map(|p| (p.x, p.y, p.color)).collect(); + + Ok(output_frame) +} + +fn main() -> Result<()> { + let matches = app_from_crate!() + .args(&[Arg::with_name("default-weight") + .short("w") + .takes_value(true) + .multiple(false) + .default_value("0")]) + .get_matches(); + + let default_weight = matches.value_of("default-weight").unwrap().parse().unwrap(); + + loop { + let mut line = String::new(); + io::stdin().read_line(&mut line)?; + + serde_json::to_writer(io::stdout(), &optimize_line(default_weight, &line)?)?; + io::stdout().write(b"\n")?; + io::stdout().flush()?; + } +} + +#[test] +fn optimize_line_test() { + optimize_line(0, "[[100.0, 100.0, 65280], [100.0, 500.0, 65280], [500.0, 500.0, 65280], [500.0, 100.0, 65280], [100.0, 100.0, 65280]]").unwrap(); +}