From 70b5188de306b70cdf8a397dd4e0ee31f07050c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Manuel=20Tom=C3=A1s?= Date: Sun, 17 Jan 2021 20:25:58 -0300 Subject: Fix curve overextending past last control point --- src/lerp.rs | 4 +- src/lib.rs | 62 ++++++++++++++++++++++++++++++ src/main.rs | 68 ++++++++++++++++++++------------ src/poly.rs | 115 ------------------------------------------------------- src/poly/iter.rs | 38 ------------------ 5 files changed, 108 insertions(+), 179 deletions(-) create mode 100644 src/lib.rs delete mode 100644 src/poly.rs delete mode 100644 src/poly/iter.rs (limited to 'src') diff --git a/src/lerp.rs b/src/lerp.rs index 818c686..b613620 100644 --- a/src/lerp.rs +++ b/src/lerp.rs @@ -1,4 +1,6 @@ -use crate::poly::Poly; +pub mod poly; + +use poly::Poly; pub enum Lerp { Node(Box, Box), diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..cadef3c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,62 @@ +mod lerp; + +use lerp::Lerp; +use lerp::poly::Poly; + +pub struct Bezier { + pub vx: Vec, + pub vy: Vec, + pub px: Poly, + pub py: Poly, + pub degree: usize +} + +impl Bezier { + pub fn new() -> Bezier { + Bezier { + vx: Vec::::new(), + vy: Vec::::new(), + px: Poly::new(vec![]), + py: Poly::new(vec![]), + degree: 0, + } + } + + pub fn push(&mut self, x: i32, y: i32) { + self.vx.push(x as f32); + self.vy.push(y as f32); + self.px = Lerp::new(self.vx.clone()).to_poly(); + self.py = Lerp::new(self.vy.clone()).to_poly(); + self.degree += 1; + } + + pub fn remove(&mut self, index: usize) { + self.vx.remove(index); + self.vy.remove(index); + self.px = Lerp::new(self.vx.clone()).to_poly(); + self.py = Lerp::new(self.vy.clone()).to_poly(); + self.degree -= 1; + } + + pub fn show_x(&self) -> String{ + let mut s = String::new(); + for i in 0..self.degree { + s.push_str(&self.vx[i].to_string()); + if i < self.degree - 1 { + s.push_str(", "); + } + } + s + } + + pub fn show_y(&self) -> String { + let mut s = String::new(); + for i in 0..self.degree { + s.push_str(&self.vy[i].to_string()); + if i < self.degree - 1 { + s.push_str(", "); + } + } + s + } +} diff --git a/src/main.rs b/src/main.rs index ee508e1..2c5dbcc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,4 @@ -mod lerp; -mod poly; - -use lerp::Lerp; -use poly::Poly; +use bezier::Bezier; use std::ffi::{CStr, CString}; @@ -25,7 +21,7 @@ fn shader_from_source(source: &CStr, shader_type: GLenum) -> GLuint { } } -fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint { +fn compile_bezier_shader(c: Bezier) -> GLuint { let vertex_shader_source = b" #version 410 core layout (location = 0) in vec3 aPos; @@ -41,34 +37,48 @@ fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint { #version 410 core out vec4 FragColor; - float pa[{sa}] = float[{sa}]({pa}); - float pb[{sb}] = float[{sb}]({pb}); + float inf = 1000000; + float vx[{s}] = float[{s}]({vx}); + float vy[{s}] = float[{s}]({vy}); + float px[{sx}] = float[{sx}]({px}); + float py[{sy}] = float[{sy}]({py}); + float thr = 32; - float eval_a(float[{sa}] v, float t) {{ + float eval_a(float[{sx}] v, float t) {{ float result = 0.0; - for (int i = 0; i < {sa}; i++) {{ + for (int i = 0; i < {sx}; i++) {{ result += v[i] * pow(t, i); }} return result; }} - float eval_b(float[{sb}] v, float t) {{ + float eval_b(float[{sy}] v, float t) {{ float result = 0.0; - for (int i = 0; i < {sb}; i++) {{ + for (int i = 0; i < {sy}; i++) {{ result += v[i] * pow(t, i); }} return result; }} + float control(vec2 pos) {{ + float closest = inf; + for (int i = 0; i < {s}; i++) {{ + float d = distance(pos, vec2(vx[i], vy[i])); + if (d < closest) {{ + closest = d; + }} + }} + return 1 - closest / thr; + }} + float inside(vec2 pos) {{ float res = 100; - float thr = 32; - float closest = 1000000; + float closest = inf; float t = 0.0; - while (t < 1.0) {{ + while (t < 1.0 - 1.0 / res) {{ float step = t + 1.0 / res; - vec2 a = vec2(eval_a(pa, t), eval_b(pb, t)); - vec2 b = vec2(eval_a(pa, step), eval_b(pb, step)); + vec2 a = vec2(eval_a(px, t), eval_b(py, t)); + vec2 b = vec2(eval_a(px, step), eval_b(py, step)); float c = pow(length(a - b), 2); float d = distance(pos, a + clamp(dot(pos - a, b - a) / c, 0, 1) * (b - a)); if (d < closest) {{ @@ -81,13 +91,17 @@ fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint { void main() {{ float r = inside(gl_FragCoord.xy); - FragColor = vec4(r * 0.8, r * 0.2, r, 1.0); + float c = control(gl_FragCoord.xy); + FragColor = vec4(r, c, 0.0, 1.0); }} ", - sa = a.degree() + 1, - sb = b.degree() + 1, - pa = &a, - pb = &b + sx = c.px.degree() + 1, + sy = c.py.degree() + 1, + px = &c.px, + py = &c.py, + s = c.degree, + vx = c.show_x(), + vy = c.show_y(), ) .into_bytes(); @@ -112,8 +126,12 @@ fn compile_bezier_shader(a: Poly, b: Poly) -> GLuint { } fn main() { - let a = Lerp::new(vec![200.0, 500.0, 500.0]).to_poly(); - let b = Lerp::new(vec![200.0, 500.0, 200.0]).to_poly(); + let mut curve = Bezier::new(); + curve.push(200, 200); + curve.push(300, 800); + curve.push(800, 100); + curve.push(1300, 800); + curve.push(1400, 200); let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); @@ -167,7 +185,7 @@ fn main() { gl::EnableVertexAttribArray(0); } - let shader_program = compile_bezier_shader(a, b); + let shader_program = compile_bezier_shader(curve); let mut event_pump = sdl_context.event_pump().unwrap(); 'running: loop { diff --git a/src/poly.rs b/src/poly.rs deleted file mode 100644 index c76e481..0000000 --- a/src/poly.rs +++ /dev/null @@ -1,115 +0,0 @@ -mod iter; - -use iter::Iter; -use std::fmt; -use std::ops::{Add, Mul, Sub}; - -#[derive(PartialEq, Debug, Clone)] -pub struct Poly { - data: Vec, - degree: usize, -} - -impl Poly { - pub fn new(data: Vec) -> Poly { - let mut i = data.len() - 1; - while data[i] == 0.0 && i > 0 { - i -= 1; - } - Poly { data, degree: i } - } - - pub fn degree(&self) -> usize { - self.degree - } - - fn iter(&self) -> Iter { - Iter::new(self.data.clone(), self.degree()) - } -} - -impl Add for &Poly { - type Output = Poly; - - fn add(self, other: Self) -> Poly { - Poly::new(self.iter().zip(other.iter()).map(|(x, y)| x + y).collect()) - } -} - -impl Sub for &Poly { - type Output = Poly; - - fn sub(self, other: Self) -> Poly { - Poly::new(self.iter().zip(other.iter()).map(|(x, y)| x - y).collect()) - } -} - -impl Mul for &Poly { - type Output = Poly; - - fn mul(self, other: Self) -> Poly { - let mut r = Vec::new(); - for i in 0..other.degree() + 1 { - let mut prefix = vec![0.0; i]; - let mut suffix: Vec = self - .iter() - .take(self.degree() + 1) - .map(|x| x * other.data[i]) - .collect(); - prefix.append(&mut suffix); - r.push(Poly::new(prefix)); - } - r.iter().fold(Poly::new(vec![0.0]), |acc, x| &acc + x) - } -} - -impl fmt::Display for &Poly { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut s = String::new(); - for i in 0..self.data.len() { - s.push_str(&self.data[i].clone().to_string()); - if i < self.data.len() - 1 { - s.push_str(", "); - } - } - write!(f, "{}", s) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn mul_test() { - let a = Poly::new(vec![1.0, 2.0, 3.0]); - let b = Poly::new(vec![1.0, 2.0]); - assert_eq!(&a * &b, Poly::new(vec![1.0, 4.0, 7.0, 6.0])); - } - - #[test] - fn add_test() { - let a = Poly::new(vec![1.0]); - let b = Poly::new(vec![0.0, 0.0, 0.0, 1.0]); - assert_eq!(&a + &b, Poly::new(vec![1.0, 0.0, 0.0, 1.0])); - } - - #[test] - fn sub_test() { - let a = Poly::new(vec![1.0, 2.0, 3.0]); - let b = Poly::new(vec![1.0, 1.0, 1.0]); - assert_eq!(&a - &b, Poly::new(vec![0.0, 1.0, 2.0])); - } - - #[test] - fn degree_is_five() { - let p = Poly::new(vec![0.0, 0.0, 0.0, 0.0, 0.0, 2.0]); - assert_eq!(p.degree(), 5); - } - - #[test] - fn degree_is_zero() { - let p = Poly::new(vec![0.0; 6]); - assert_eq!(p.degree(), 0); - } -} diff --git a/src/poly/iter.rs b/src/poly/iter.rs deleted file mode 100644 index 90cc4b5..0000000 --- a/src/poly/iter.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::cmp; -use std::iter::{Take, Zip}; - -pub struct Iter { - index: usize, - data: Vec, - degree: usize, -} - -impl Iter { - pub fn new(data: Vec, degree: usize) -> Iter { - Iter { - index: 0, - data, - degree, - } - } - - pub fn zip(self, other: Self) -> Zip, Take> { - let deg = cmp::max(self.degree, other.degree) + 1; - let a = self.take(deg); - let b = other.take(deg); - a.zip(b) - } -} - -impl Iterator for Iter { - type Item = f32; - - fn next(&mut self) -> Option { - self.index += 1; - if self.index <= self.data.len() { - Some(self.data[self.index - 1]) - } else { - Some(0.0) - } - } -} -- cgit v1.2.3