del_canvas/rasterize/
line2.rs

1use num_traits::AsPrimitive;
2
3/// draw line using DDA method.
4pub fn draw_dda_pixel_coordinate<Real, VAL>(
5    img_data: &mut [VAL],
6    width: usize,
7    p0: &[Real; 2],
8    p1: &[Real; 2],
9    i_color: VAL,
10) where
11    Real: num_traits::Float + 'static + AsPrimitive<usize> + std::fmt::Debug,
12    usize: AsPrimitive<Real>,
13    VAL: Copy,
14{
15    let height = img_data.len() / width;
16    let width_f: Real = width.as_();
17    let height_f: Real = height.as_();
18    let zero = Real::zero();
19    let dx = p1[0] - p0[0];
20    let dy = p1[1] - p0[1];
21    let step = if dx.abs() > dy.abs() {
22        dx.abs()
23    } else {
24        dy.abs()
25    };
26    let slope_y = dy / step;
27    let slope_x = dx / step;
28    let mut x = p0[0];
29    let mut y = p0[1];
30    while (x - p0[0]).abs() <= (p1[0] - p0[0]).abs() && (y - p0[1]).abs() <= (p1[1] - p0[1]).abs() {
31        if x >= zero && x < width_f && y >= zero && y < height_f {
32            let ix: usize = x.as_();
33            let iy: usize = y.as_();
34            img_data[iy * width + ix] = i_color;
35        }
36        x = x + slope_x;
37        y = y + slope_y;
38    }
39}
40
41/// * `transform` - 3x3 homogeneous transformation matrix with **column major** order
42pub fn draw_dda<Real, VAL>(
43    img_data: &mut [VAL],
44    width: usize,
45    p0: &[Real; 2],
46    p1: &[Real; 2],
47    transform: &[Real; 9],
48    i_color: VAL,
49) where
50    Real: num_traits::Float + std::fmt::Debug + 'static + AsPrimitive<usize>,
51    usize: AsPrimitive<Real>,
52    VAL: Copy,
53{
54    let q0 = del_geo_core::mat3_col_major::transform_homogeneous(transform, p0).unwrap();
55    let q1 = del_geo_core::mat3_col_major::transform_homogeneous(transform, p1).unwrap();
56    draw_dda_pixel_coordinate(img_data, width, &q0, &q1, i_color);
57}
58
59pub fn pixels_in_line<Real>(
60    x0: Real,
61    y0: Real,
62    x1: Real,
63    y1: Real,
64    rad: Real,
65    width: usize,
66    height: usize,
67) -> Vec<usize>
68where
69    Real: num_traits::Float + 'static + AsPrimitive<usize>,
70    usize: AsPrimitive<Real>,
71{
72    let half: Real = Real::one() / (Real::one() + Real::one());
73    let aabbi = {
74        let aabb = del_geo_core::aabb2::from_two_points(&[x0, y0], &[x1, y1], rad);
75        del_geo_core::aabb2::rasterize(&aabb, &(width, height))
76    };
77    let sqlen = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
78    let mut res = Vec::<usize>::new();
79    for ih in aabbi[1]..aabbi[3] {
80        for iw in aabbi[0]..aabbi[2] {
81            let w: Real = iw.as_() + half; // pixel center
82            let h: Real = ih.as_() + half; // pixel center
83            let t = ((w - x0) * (x1 - x0) + (h - y0) * (y1 - y0)) / sqlen;
84            let sqdist = if t < Real::zero() {
85                (w - x0) * (w - x0) + (h - y0) * (h - y0)
86            } else if t > Real::one() {
87                (w - x1) * (w - x1) + (h - y1) * (h - y1)
88            } else {
89                (w - x0) * (w - x0) + (h - y0) * (h - y0) - sqlen * t * t
90            };
91            if sqdist > rad * rad {
92                continue;
93            }
94            res.push(ih * width + iw);
95        }
96    }
97    res
98}
99
100/// * `transform` - 3x3 homogeneous transformation matrix with **column major** order
101pub fn draw_pixcenter<T, VAL>(
102    img_data: &mut [VAL],
103    width: usize,
104    p0: &[T; 2],
105    p1: &[T; 2],
106    transform_world2pix: &[T; 9],
107    thickness: T,
108    color: VAL,
109) where
110    T: num_traits::Float + num_traits::AsPrimitive<usize>,
111    usize: AsPrimitive<T>,
112    VAL: Copy,
113{
114    let height = img_data.len() / width;
115    let a0 = del_geo_core::mat3_col_major::transform_homogeneous(transform_world2pix, p0).unwrap();
116    let a1 = del_geo_core::mat3_col_major::transform_homogeneous(transform_world2pix, p1).unwrap();
117    let pixs = pixels_in_line(a0[0], a0[1], a1[0], a1[1], thickness, width, height);
118    for i_data in pixs {
119        img_data[i_data] = color;
120    }
121}