Compare commits
1 Commits
c1950fd234
...
137f269b47
Author | SHA1 | Date | |
---|---|---|---|
137f269b47 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -10,3 +10,8 @@ Cargo.lock
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
|
||||
|
||||
#Added by cargo
|
||||
|
||||
/target
|
||||
|
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "lasy-cli"
|
||||
version = "0.1.0"
|
||||
authors = ["Leo Le Bouter <lle-bout@zaclys.net>"]
|
||||
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"
|
156
src/main.rs
Normal file
156
src/main.rs
Normal file
@ -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<H: Hasher>(&self, hasher: &mut H) {
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct HashPoint {
|
||||
x: u32,
|
||||
y: u32,
|
||||
color: u32,
|
||||
}
|
||||
|
||||
impl From<Point> 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<Vec<InputArrayEntry>> {
|
||||
let frame: Vec<InputArrayEntry> = serde_json::from_str(line)?;
|
||||
|
||||
let input_points: Vec<Point> = 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<Point> = 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user