summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJuan Manuel Tomás <jtomas1815@gmail.com>2021-01-17 20:25:58 -0300
committerJuan Manuel Tomás <jtomas1815@gmail.com>2021-01-17 20:25:58 -0300
commit70b5188de306b70cdf8a397dd4e0ee31f07050c8 (patch)
tree3721070393126b79a3658fe8a89f1fa98a84db44 /src
parent18efe0d28ebcd936ea50275a351ef1c30253ea1c (diff)
downloadbezier-70b5188de306b70cdf8a397dd4e0ee31f07050c8.tar.gz
bezier-70b5188de306b70cdf8a397dd4e0ee31f07050c8.zip
Fix curve overextending past last control point
Diffstat (limited to 'src')
-rw-r--r--src/lerp.rs4
-rw-r--r--src/lib.rs62
-rw-r--r--src/main.rs68
-rw-r--r--src/poly.rs115
-rw-r--r--src/poly/iter.rs38
5 files changed, 108 insertions, 179 deletions
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<Lerp>, Box<Lerp>),
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<f32>,
+ pub vy: Vec<f32>,
+ pub px: Poly,
+ pub py: Poly,
+ pub degree: usize
+}
+
+impl Bezier {
+ pub fn new() -> Bezier {
+ Bezier {
+ vx: Vec::<f32>::new(),
+ vy: Vec::<f32>::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<f32>,
- degree: usize,
-}
-
-impl Poly {
- pub fn new(data: Vec<f32>) -> 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<f32> = 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<f32>,
- degree: usize,
-}
-
-impl Iter {
- pub fn new(data: Vec<f32>, degree: usize) -> Iter {
- Iter {
- index: 0,
- data,
- degree,
- }
- }
-
- pub fn zip(self, other: Self) -> Zip<Take<Iter>, Take<Iter>> {
- 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<f32> {
- self.index += 1;
- if self.index <= self.data.len() {
- Some(self.data[self.index - 1])
- } else {
- Some(0.0)
- }
- }
-}