diff --git a/Cargo.toml b/Cargo.toml index 7d1ddc4..1b1bde0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ exclude = ["tdata", "benches/", ".gitignore"] [dependencies] mattr = "0.0.2" png = { version = "0.17", features = ["unstable"], optional = true } +vecto = "0.1.0" [dev-dependencies] iai = { version = "0.1.1", features = [ diff --git a/src/drawing/line.rs b/src/drawing/line.rs index 3498d95..e1dde96 100644 --- a/src/drawing/line.rs +++ b/src/drawing/line.rs @@ -2,6 +2,7 @@ #![allow(clippy::missing_docs_in_private_items)] use crate::Image; use std::iter::Iterator; +use vecto::Vec2; /// taken from [bresenham-rs](https://github.com/mbr/bresenham-rs) pub struct Bresenham { @@ -156,20 +157,18 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { /// ``` pub fn thick_line( &mut self, - (x1, y1): (f32, f32), - (x2, y2): (f32, f32), + a: impl Into, + b: impl Into, stroke: f32, color: [u8; CHANNELS], ) { - let (wx, wy) = { - let (x, y) = (y1 - y2, -(x1 - x2)); - let l = (x * x + y * y).sqrt(); - ((x / l) * (stroke / 2.0), (y / l) * (stroke / 2.0)) - }; + let a = a.into(); + let b = b.into(); + let w = (a - b).orthogonal().normalized() * (stroke / 2.0); macro_rules! p { - ($x:expr,$y:expr) => { + ($x:expr) => { #[allow(clippy::cast_possible_truncation)] - ($x.round() as i32, $y.round() as i32) + ($x.x.round() as i32, $x.y.round() as i32) }; } // order: @@ -177,10 +176,10 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { // [ ] // ^ x3 ^ x4 self.quad( - p!(x1 - wx, y1 - wy), // x1 - p!(x2 - wx, y2 - wy), // x2 - p!(x2 + wx, y2 + wy), // x3 - p!(x1 + wx, y1 + wy), // x4 + p!(a - w), // x1 + p!(b - w), // x2 + p!(b + w), // x3 + p!(a + w), // x4 color, ); } diff --git a/src/drawing/poly.rs b/src/drawing/poly.rs index ecad1ab..0b8f3ac 100644 --- a/src/drawing/poly.rs +++ b/src/drawing/poly.rs @@ -2,6 +2,7 @@ use crate::math::{madd, FExt}; use std::cmp::{max, min}; use std::f32::consts::TAU; +use vecto::Vec2; use crate::Image; @@ -97,22 +98,22 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { /// ``` pub fn poly( &mut self, - (x, y): (f32, f32), + pos: impl Into, sides: usize, radius: f32, rotation: f32, c: [u8; CHANNELS], ) { - let trans = |a: f32| (a.cos() * radius, a.sin() * radius); - let r = |(a, b): (f32, f32)| (a.round() as i32, b.round() as i32); - let add = |(a, b)| (a + x, b + y); + let pos = pos.into(); + let trans = |a: f32| Vec2::from_angle(a) * radius; + let r = |v: Vec2| (v.x.round() as i32, v.y.round() as i32); match sides { 3 => { let space = TAU / 3.0; self.tri( - add(trans(space + rotation)), - add(trans(rotation)), - add(trans(madd(space, 2.0, rotation))), + trans(space + rotation) + pos, + trans(rotation) + pos, + trans(madd(space, 2.0, rotation)) + pos, c, ); } @@ -120,10 +121,10 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { let space = TAU / sides as f32; for i in (0..sides - 1).step_by(2).map(|i| i as f32) { self.quad( - r((x, y)), - r(add(trans(madd(space, i, rotation)))), - r(add(trans(madd(space, i + 1., rotation)))), - r(add(trans(madd(space, i + 2., rotation)))), + r(pos), + r(trans(madd(space, i, rotation)) + pos), + r(trans(madd(space, i + 1., rotation)) + pos), + r(trans(madd(space, i + 2., rotation)) + pos), c, ); } @@ -132,9 +133,9 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { let i = (sides - 1) as f32; // the missing piece self.tri( - (x, y), - add(trans(madd(space, i, rotation))), - add(trans(madd(space, i + 1., rotation))), + pos, + trans(madd(space, i, rotation)) + pos, + trans(madd(space, i + 1., rotation)) + pos, c, ); } @@ -152,13 +153,14 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { /// ``` pub fn border_poly( &mut self, - (x, y): (f32, f32), + pos: impl Into, sides: usize, radius: f32, rotation: f32, stroke: f32, c: [u8; CHANNELS], ) { + let pos = pos.into(); let space = TAU / sides as f32; let step = stroke / 2.0 / (space / 2.0).cos(); let r1 = radius - step; @@ -167,10 +169,16 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { for i in 0..sides { let a = space.madd(i as f32, rotation); self.quad( - r(r1.madd(a.cos(), x), r1.madd(a.sin(), y)), - r(r1.madd((a + space).cos(), x), r1.madd((a + space).sin(), y)), - r(r2.madd((a + space).cos(), x), r2.madd((a + space).sin(), y)), - r(r2.madd(a.cos(), x), r2.madd(a.sin(), y)), + r(r1.madd(a.cos(), pos.x), r1.madd(a.sin(), pos.y)), + r( + r1.madd((a + space).cos(), pos.x), + r1.madd((a + space).sin(), pos.y), + ), + r( + r2.madd((a + space).cos(), pos.x), + r2.madd((a + space).sin(), pos.y), + ), + r(r2.madd(a.cos(), pos.x), r2.madd(a.sin(), pos.y)), c, ); } diff --git a/src/drawing/tri.rs b/src/drawing/tri.rs index 1333abe..5fb90bb 100644 --- a/src/drawing/tri.rs +++ b/src/drawing/tri.rs @@ -1,4 +1,6 @@ //! trongle drawing +use vecto::Vec2; + use crate::math::madd; use crate::Image; use std::cmp::{max, min}; @@ -19,11 +21,14 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { /// ``` pub fn tri( &mut self, - (x2, y2): (f32, f32), - (x1, y1): (f32, f32), - (x3, y3): (f32, f32), - c: [u8; CHANNELS], + b: impl Into, + a: impl Into, + c: impl Into, + col: [u8; CHANNELS], ) { + let Vec2 { x: x1, y: y1 } = a.into(); + let Vec2 { x: x2, y: y2 } = b.into(); + let Vec2 { x: x3, y: y3 } = c.into(); let ymin = max(y1.min(y2).min(y3) as u32, 0); let ymax = min(y1.max(y2).max(y3) as u32, self.height()); let xmin = max(x1.min(x2).min(x3) as u32, 0); @@ -36,7 +41,7 @@ impl + AsRef<[u8]>, const CHANNELS: usize> Image { && madd(x3 - x1, y as f32 - y3, -(y3 - y1) * (x as f32 - x3)) > 0. { // SAFETY: x, y are bounded - unsafe { self.set_pixel(x, y, c) }; + unsafe { self.set_pixel(x, y, col) }; } } } diff --git a/src/lib.rs b/src/lib.rs index 1427562..cd82ba8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,6 +254,7 @@ impl Image<[u8; N], CHANNELS> { impl Image<&[u8], CHANNELS> { /// Box this image. pub fn boxed(self) -> Image, CHANNELS> { + // SAFETY: ctor unsafe { Image::new(self.width, self.height, self.buffer.into()) } } }