use vec2's

This commit is contained in:
bendn 2023-10-15 10:22:38 +07:00
parent cd17b4860f
commit c264f735ce
No known key found for this signature in database
GPG key ID: 0D9D3A2A3B2A93D6
5 changed files with 51 additions and 37 deletions

View file

@ -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 = [

View file

@ -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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// ```
pub fn thick_line(
&mut self,
(x1, y1): (f32, f32),
(x2, y2): (f32, f32),
a: impl Into<Vec2>,
b: impl Into<Vec2>,
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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
// [ ]
// ^ 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,
);
}

View file

@ -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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// ```
pub fn poly(
&mut self,
(x, y): (f32, f32),
pos: impl Into<Vec2>,
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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// ```
pub fn border_poly(
&mut self,
(x, y): (f32, f32),
pos: impl Into<Vec2>,
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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
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,
);
}

View file

@ -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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// ```
pub fn tri(
&mut self,
(x2, y2): (f32, f32),
(x1, y1): (f32, f32),
(x3, y3): (f32, f32),
c: [u8; CHANNELS],
b: impl Into<Vec2>,
a: impl Into<Vec2>,
c: impl Into<Vec2>,
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<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
&& 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) };
}
}
}

View file

@ -254,6 +254,7 @@ impl<const CHANNELS: usize, const N: usize> Image<[u8; N], CHANNELS> {
impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
/// Box this image.
pub fn boxed(self) -> Image<Box<[u8]>, CHANNELS> {
// SAFETY: ctor
unsafe { Image::new(self.width, self.height, self.buffer.into()) }
}
}