rasterization/
lib.rs

1#![crate_name = "rasterization"]
2#![no_std]
3#![forbid(unsafe_code)]
4#![warn(
5    missing_docs,
6    missing_debug_implementations,
7    missing_copy_implementations
8)]
9#![doc(
10    html_logo_url = "https://raw.githubusercontent.com/pic16f877ccs/image/pixelization/quadrant_parts.png"
11)]
12#![doc = include_str!("../README.md")]
13//! <style>
14//!     .rustdoc-hidden { display: none; }
15//! </style>
16use colorous::Gradient;
17use core::fmt::{Debug, Display};
18use core::iter::FusedIterator;
19use core::ops::{Add, AddAssign, Mul, Neg, Range, Sub};
20use num::{One, Unsigned, Zero};
21use num_convert::FromAs;
22
23/// Enum for selecting the gradient direction and setting the color gradient type.
24#[derive(Debug, Clone, Copy)]
25pub enum DirectionGradient {
26    /// The gradient direction is from bottom to top.
27    Top(Gradient),
28    /// The gradient direction is from top to bottom.
29    Bottom(Gradient),
30    /// The gradient direction is from left to right.
31    Right(Gradient),
32    /// The gradient direction is from right to left.
33    Left(Gradient),
34    /// The gradient direction is from bottom right to top left.
35    TopLeft(Gradient),
36    /// The gradient direction is from bottom left to top right.
37    TopRight(Gradient),
38    /// The gradient direction is from top right to bottom left.
39    BottomLeft(Gradient),
40    /// The gradient direction is from top left to bottom rightt.
41    BottomRight(Gradient),
42}
43
44/// An iterator of successive coordinates of a filled semicircle, using Bresenham's algorithm.
45///
46/// The semicircles are exactly equal in diameter to the circle.
47#[derive(Default, Debug, Clone, PartialEq)]
48pub struct SemicircleFilled<T> {
49    x: T,
50    y: T,
51    err: T,
52}
53
54impl<T> SemicircleFilled<T> {
55    /// Creates a new `SemicircleFilled` iterator that generates pixel coordinates.
56    ///
57    /// # Panics
58    ///
59    /// This function will panic if the radius cannot be converted to type `T` or
60    ///
61    /// if the radius exceeds the practical limit of 100,000,000.
62    ///
63    /// This limit exists to prevent overflow in the calculation of the error term.
64    ///
65    /// # Arguments
66    ///
67    /// * `radius` - A non-negative integer representing the radius of the semicircle.
68    ///
69    /// # Examples
70    ///
71    /// Basic usage:
72    ///
73    /// ```rust
74    /// use rasterization::SemicircleFilled;
75    ///
76    /// let radius = 5_u32;
77    /// let semicircle_iter = SemicircleFilled::<i32>::new(radius);
78    /// let vec = semicircle_iter.collect::<Vec<_>>();
79    /// assert_eq!(vec, vec![(-5..5, -1), (-5..5, -2), (-4..4, -3), (-3..3, -4), (-2..2, -5)]);
80    /// ```
81    #[inline]
82    pub fn new<U>(radius: U) -> Self
83    where
84        U: Unsigned + Display + Copy,
85        T: From<i8>
86            + TryFrom<U>
87            + Sub<Output = T>
88            + Neg<Output = T>
89            + Default
90            + Mul<Output = T>
91            + FromAs<isize>
92            + PartialOrd
93            + Copy,
94        <T as TryFrom<U>>::Error: Debug,
95    {
96        let Ok(r) = <T as TryFrom<U>>::try_from(radius) else {
97            panic!(
98                "{}",
99                format_args!("Not possible to convert radius to {}", radius)
100            )
101        };
102        let m_radius = <T as FromAs<isize>>::from_as(100_000_000_isize);
103        if r < m_radius {
104            return Self {
105                x: -r,
106                y: 0.into(),
107                err: <T as From<i8>>::from(2) - <T as From<i8>>::from(2) * r,
108            };
109        }
110
111        panic!("Radius is too large")
112    }
113}
114
115impl Iterator for SemicircleFilled<i32> {
116    type Item = (Range<i32>, i32);
117
118    #[inline]
119    fn next(&mut self) -> Option<Self::Item> {
120        if self.x == 0 {
121            return None;
122        }
123
124        let xy = (self.x..-self.x, -(self.y + 1));
125
126        // FIXME: This loop creates redundant iterations!
127        loop {
128            let y_tmp = self.y;
129            let err_tmp = self.err;
130
131            if err_tmp <= self.y {
132                self.y += 1;
133                self.err += 2 * self.y + 2;
134            };
135
136            if err_tmp > self.x || self.err > self.y {
137                self.x += 1;
138                self.err += 2 * self.x + 2;
139            }
140
141            if y_tmp != self.y || self.x == 0 {
142                break;
143            }
144        }
145
146        Some(xy)
147    }
148}
149
150impl Iterator for SemicircleFilled<isize> {
151    type Item = (Range<isize>, isize);
152
153    #[inline]
154    fn next(&mut self) -> Option<Self::Item> {
155        if self.x == 0 {
156            return None;
157        }
158
159        let xy = (self.x..-self.x, -(self.y + 1));
160
161        // FIXME: This loop creates redundant iterations!
162        loop {
163            let y_tmp = self.y;
164            let err_tmp = self.err;
165
166            if err_tmp <= self.y {
167                self.y += 1;
168                self.err += 2 * self.y + 2;
169            };
170
171            if err_tmp > self.x || self.err > self.y {
172                self.x += 1;
173                self.err += 2 * self.x + 2;
174            }
175
176            if y_tmp != self.y || self.x == 0 {
177                break;
178            }
179        }
180
181        Some(xy)
182    }
183}
184
185impl Iterator for SemicircleFilled<i64> {
186    type Item = (Range<i64>, i64);
187
188    #[inline]
189    fn next(&mut self) -> Option<Self::Item> {
190        if self.x == 0 {
191            return None;
192        }
193
194        let xy = (self.x..-self.x, -(self.y + 1));
195
196        // FIXME: This loop creates redundant iterations!
197        loop {
198            let y_tmp = self.y;
199            let err_tmp = self.err;
200
201            if err_tmp <= self.y {
202                self.y += 1;
203                self.err += 2 * self.y + 2;
204            };
205
206            if err_tmp > self.x || self.err > self.y {
207                self.x += 1;
208                self.err += 2 * self.x + 2;
209            }
210
211            if y_tmp != self.y || self.x == 0 {
212                break;
213            }
214        }
215
216        Some(xy)
217    }
218}
219
220impl<T> FusedIterator for SemicircleFilled<T> where SemicircleFilled<T>: Iterator {}
221
222/// The trait for rasterization of given figures.
223pub trait Rasterization: Iterator {
224    /// An iterator adapter that creates (x, y) coordinates for the filled full circle.
225    ///
226    /// # Examples
227    ///
228    /// Basic usage:
229    ///
230    /// ```rust
231    /// use rasterization::{Rasterization, SemicircleFilled};
232    ///
233    /// let iter = SemicircleFilled::<i32>::new(2_usize).circle();
234    /// let vec = iter.collect::<Vec<_>>();
235    /// assert_eq!(vec, vec![(-2, -1), (-2, 0), (-1, -1), (-1, 0), (0, -1), (0, 0),
236    ///           (1, -1), (1, 0), (-1, -2), (-1, 1), (0, -2), (0, 1)]);
237    /// ```
238    #[inline]
239    fn circle<T, R>(self) -> impl Iterator<Item = (T, T)> + Clone + Debug
240    where
241        Self: Sized + Iterator<Item = (R, T)> + Clone + Debug,
242        T: Add<Output = T> + One + Sub<Output = T> + Neg<Output = T> + Copy + Debug,
243        R: Iterator<Item = T> + Clone + Debug,
244    {
245        self.flat_map(|(range, y)| range.flat_map(move |x| [(x, y), (x, -y - T::one())]))
246    }
247
248    /// The iterator adapter adds an offset to a two-element tuple.
249    ///
250    /// # Examples
251    ///
252    /// Basic usage:
253    ///
254    /// ```rust
255    ///
256    /// use rasterization::{Rasterization, SemicircleFilled};
257    ///
258    /// let radius = 2_usize;
259    /// let offset_x = radius as i32;
260    /// let offset_y = radius as i32;
261    /// let iter = SemicircleFilled::<i32>::new(radius).circle().offset(offset_x, offset_y);
262    /// let vec = iter.collect::<Vec<_>>();
263    /// assert_eq!(vec, vec![(0, 1), (0, 2), (1, 1), (1, 2), (2, 1), (2, 2),
264    ///           (3, 1), (3, 2), (1, 0), (1, 3), (2, 0), (2, 3)]);
265    /// ```
266    #[inline]
267    fn offset<T>(self, offset_x: T, offset_y: T) -> impl Iterator<Item = (T, T)> + Clone + Debug
268    where
269        Self: Sized + Iterator<Item = (T, T)> + Clone + Debug,
270        T: Add<Output = T> + Copy + Debug,
271    {
272        self.map(move |(x, y)| (x + offset_x, y + offset_y))
273    }
274
275    /// An iterator adapter that creates (x, y) coordinates for the filled long circle.
276    ///
277    /// # Examples
278    ///
279    /// Basic usage:
280    ///
281    /// ```rust
282    /// use rasterization::{Rasterization, SemicircleFilled};
283    ///
284    /// let iter = SemicircleFilled::<i32>::new(2_u64).circle_long(1, -1);
285    /// let vec = iter.collect::<Vec<_>>();
286    /// assert_eq!(vec, vec![(-1, -1), (-1, 0), (0, -1), (0, 0)]);
287    /// ```
288    #[inline]
289    fn circle_long<T>(self, start: T, end: T) -> impl Iterator<Item = (T, T)> + Clone + Debug
290    where
291        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
292        T: Add<Output = T> + One + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign + Debug,
293        Range<T>: Iterator<Item = T> + Clone + Debug,
294    {
295        self.flat_map(move |(mut range, y)| {
296            range.start += start;
297            range.end += end;
298            range.flat_map(move |x| [(x, y), (x, -y - T::one())])
299        })
300    }
301
302    /// An iterator adapter that creates (x, y) coordinates for the filled top semicircle.
303    ///
304    /// # Examples
305    ///
306    /// Basic usage:
307    ///
308    /// ```rust
309    /// use rasterization::{Rasterization, SemicircleFilled};
310    ///
311    /// let iter = SemicircleFilled::<isize>::new(2_u8).semicircle_top();
312    /// let vec = iter.collect::<Vec<_>>();
313    /// assert_eq!(vec, vec![(-2, -1), (-1, -1), (0, -1), (1, -1), (-1, -2), (0, -2)]);
314    /// ```
315    #[inline]
316    fn semicircle_top<T, R>(self) -> impl Iterator<Item = (T, T)> + Clone + Debug
317    where
318        Self: Sized + Iterator<Item = (R, T)> + Clone + Debug,
319        T: Add<Output = T> + One + Sub<Output = T> + Neg<Output = T> + Copy,
320        R: Iterator<Item = T> + Clone + Debug,
321    {
322        self.flat_map(|(range, y)| range.map(move |x| (x, y)))
323    }
324
325    /// An iterator adapter that creates (x, y) coordinates for the filled bottom semicircle.
326    ///
327    /// # Examples
328    ///
329    /// Basic usage:
330    ///
331    /// ```rust
332    /// use rasterization::{Rasterization, SemicircleFilled};
333    ///
334    /// let iter = SemicircleFilled::<isize>::new(2_u16).semicircle_bottom();
335    /// let vec = iter.collect::<Vec<_>>();
336    /// assert_eq!(vec, vec![(-2, 0), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1)]);
337    /// ```
338    #[inline]
339    fn semicircle_bottom<T, R>(self) -> impl Iterator<Item = (T, T)> + Clone + Debug
340    where
341        Self: Sized + Iterator<Item = (R, T)> + Clone + Debug,
342        T: Add<Output = T> + One + Sub<Output = T> + Neg<Output = T> + Copy,
343        R: Iterator<Item = T> + Clone + Debug,
344    {
345        self.flat_map(|(range, y)| range.map(move |x| (x, -y - T::one())))
346    }
347
348    /// An iterator adapter that creates (x, y) coordinates for the filled top long semicircle.
349    ///
350    /// # Examples
351    ///
352    /// Basic usage:
353    ///
354    /// ```rust
355    /// use rasterization::{Rasterization, SemicircleFilled};
356    ///
357    /// let iter = SemicircleFilled::<isize>::new(2_u32).semicircle_top_long(0, 1);
358    /// let vec = iter.collect::<Vec<_>>();
359    /// assert_eq!(vec, vec![(-2, -1), (-1, -1), (0, -1), (1, -1), (2, -1), (-1, -2), (0, -2), (1, -2)]);
360    /// ```
361    #[inline]
362    fn semicircle_top_long<T>(
363        self,
364        start: T,
365        end: T,
366    ) -> impl Iterator<Item = (T, T)> + Clone + Debug
367    where
368        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
369        T: Add<Output = T> + One + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign,
370        Range<T>: Iterator<Item = T> + Clone + Debug,
371    {
372        self.flat_map(move |(mut range, y)| {
373            range.start += start;
374            range.end += end;
375            range.map(move |x| (x, y))
376        })
377    }
378
379    /// An iterator adapter that creates (x, y) coordinates for the filled bottom long semicircle.
380    ///
381    /// # Examples
382    ///
383    /// Basic usage:
384    ///
385    /// ```rust
386    /// use rasterization::{Rasterization, SemicircleFilled};
387    ///
388    /// let iter = SemicircleFilled::<isize>::new(2_usize).semicircle_bottom_long(0, 1);
389    /// let vec = iter.collect::<Vec<_>>();
390    /// assert_eq!(vec, vec![(-2, 0), (-1, 0), (0, 0), (1, 0), (2, 0), (-1, 1), (0, 1), (1, 1)]);
391    /// ```
392    #[inline]
393    fn semicircle_bottom_long<T>(
394        self,
395        start: T,
396        end: T,
397    ) -> impl Iterator<Item = (T, T)> + Clone + Debug
398    where
399        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
400        T: Add<Output = T> + One + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign,
401        Range<T>: Iterator<Item = T> + Clone + Debug,
402    {
403        self.flat_map(move |(mut range, y)| {
404            range.start += start;
405            range.end += end;
406            range.map(move |x| (x, -y - T::one()))
407        })
408    }
409
410    /// An iterator adapter that creates the (x, y) coordinates for the filled circle of the first quadrant.
411    ///
412    /// # Examples
413    ///
414    /// Basic usage:
415    ///
416    /// ```rust
417    /// use rasterization::{Rasterization, SemicircleFilled};
418    ///
419    /// let iter = SemicircleFilled::<isize>::new(3_u64).first_quadrant(0);
420    /// let vec = iter.collect::<Vec<_>>();
421    /// assert_eq!(vec, vec![(0, -1), (1, -1), (2, -1), (0, -2), (1, -2), (2, -2), (0, -3), (1, -3)]);
422    /// ```
423    #[inline]
424    fn first_quadrant<T>(self, end: T) -> impl Iterator<Item = (T, T)> + Clone + Debug
425    where
426        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
427        T: Add<Output = T> + Zero + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign,
428        Range<T>: Iterator<Item = T> + Clone + Debug,
429    {
430        self.flat_map(move |(mut range, y)| {
431            range.start = T::zero();
432            range.end += end;
433            range.map(move |x| (x, y))
434        })
435    }
436
437    /// An iterator adapter that creates the (x, y) coordinates for the filled circle of the second quadrant.
438    ///
439    /// # Examples
440    ///
441    /// Basic usage:
442    ///
443    /// ```rust
444    /// use rasterization::{Rasterization, SemicircleFilled};
445    ///
446    /// let iter = SemicircleFilled::<i64>::new(3_u8).second_quadrant(0);
447    /// let vec = iter.collect::<Vec<_>>();
448    /// assert_eq!(vec, vec![(-3, -1), (-2, -1), (-1, -1), (-3, -2), (-2, -2), (-1, -2), (-2, -3), (-1, -3)]);
449    /// ```
450    #[inline]
451    fn second_quadrant<T>(self, end: T) -> impl Iterator<Item = (T, T)> + Clone + Debug
452    where
453        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
454        T: Add<Output = T> + Zero + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign,
455        Range<T>: Iterator<Item = T> + Clone + Debug,
456    {
457        self.flat_map(move |(mut range, y)| {
458            range.end = T::zero() + end;
459            range.map(move |x| (x, y))
460        })
461    }
462
463    /// An iterator adapter that creates the (x, y) coordinates for the filled circle of the third quadrant.
464    ///
465    /// # Examples
466    ///
467    /// Basic usage:
468    ///
469    /// ```rust
470    /// use rasterization::{Rasterization, SemicircleFilled};
471    ///
472    /// let iter = SemicircleFilled::<i64>::new(3_u16).third_quadrant(0);
473    /// let vec = iter.collect::<Vec<_>>();
474    /// assert_eq!(vec, vec![(-3, 0), (-2, 0), (-1, 0), (-3, 1), (-2, 1), (-1, 1), (-2, 2), (-1, 2)]);
475    /// ```
476    #[inline]
477    fn third_quadrant<T>(self, end: T) -> impl Iterator<Item = (T, T)> + Clone + Debug
478    where
479        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
480        T: Add<Output = T> + One + Zero + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign,
481        Range<T>: Iterator<Item = T> + Clone + Debug,
482    {
483        self.flat_map(move |(mut range, y)| {
484            range.end = T::zero() + end;
485            range.map(move |x| (x, -y - T::one()))
486        })
487    }
488
489    /// An iterator adapter that creates the (x, y) coordinates for the filled circle of the fourth quadrant.
490    ///
491    /// # Examples
492    ///
493    /// Basic usage:
494    ///
495    /// ```rust
496    /// use rasterization::{Rasterization, SemicircleFilled};
497    ///
498    /// let iter = SemicircleFilled::<i64>::new(3_u32).fourth_quadrant(0);
499    /// let vec = iter.collect::<Vec<_>>();
500    /// assert_eq!(vec, vec![(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2)]);
501    /// ```
502    #[inline]
503    fn fourth_quadrant<T>(self, end: T) -> impl Iterator<Item = (T, T)> + Clone + Debug
504    where
505        Self: Sized + Iterator<Item = (Range<T>, T)> + Clone + Debug,
506        T: Add<Output = T> + One + Zero + Sub<Output = T> + Neg<Output = T> + Copy + AddAssign,
507        Range<T>: Iterator<Item = T> + Clone + Debug,
508    {
509        self.flat_map(move |(mut range, y)| {
510            range.start = T::zero();
511            range.end += end;
512            range.map(move |x| (x, -y - T::one()))
513        })
514    }
515
516    /// The iterator adapter fills a circle or part of it with a gradient color from crate [colorous].
517    /// Possible options are: vertical, horizontal or diagonal.
518    ///
519    /// # Examples
520    ///
521    /// Basic usage:
522    ///
523    /// ```rust
524    /// use rasterization::{Rasterization, SemicircleFilled,
525    /// DirectionGradient::BottomRight};
526    /// use colorous::Gradient;
527    ///
528    /// let radius = 256_usize;
529    /// let offset_x = radius as i32;
530    /// let offset_y = radius as i32;
531    /// let offset = (radius as f32 * 1.414).ceil() as i32;
532    /// let size = (offset * 2) as usize;
533    /// let iter = SemicircleFilled::<i32>::new(radius)
534    ///     .circle()
535    ///     .take(3)
536    ///     .gradient(offset, size, BottomRight(colorous::BROWN_GREEN));
537    /// let vec = iter.collect::<Vec<_>>();
538    /// assert_eq!(vec, vec![(-256, -1, [162, 103, 27]), (-256, 0, [163, 104, 27]), (-255, -1, [163, 104, 27])]);
539    /// ```
540    /// [colorous]: https://crates.io/crates/colorous
541    #[inline]
542    fn gradient<T>(
543        self,
544        offset: T,
545        size: usize,
546        dir_grd: DirectionGradient,
547    ) -> impl Iterator<Item = (T, T, [u8; 3])> + Clone + Debug
548    where
549        Self: Sized + Iterator<Item = (T, T)> + Clone + Debug,
550        T: Add<Output = T> + Sub<Output = T> + Copy,
551        usize: FromAs<T>,
552    {
553        self.map(move |(x, y)| {
554            let grad_arg = match dir_grd {
555                DirectionGradient::Left(grad) => (offset - x, grad),
556                DirectionGradient::TopLeft(grad) => (offset - (x + y), grad),
557                DirectionGradient::Top(grad) => (offset - y, grad),
558                DirectionGradient::TopRight(grad) => (x - y + offset, grad),
559                DirectionGradient::Right(grad) => (x + offset, grad),
560                DirectionGradient::BottomRight(grad) => (x + y + offset, grad),
561                DirectionGradient::Bottom(grad) => (y + offset, grad),
562                DirectionGradient::BottomLeft(grad) => (offset - (x - y), grad),
563            };
564
565            (
566                x,
567                y,
568                grad_arg
569                    .1
570                    .eval_rational(usize::from_as(grad_arg.0), size)
571                    .as_array(),
572            )
573        })
574    }
575}
576
577impl<T: ?Sized> Rasterization for T where T: Iterator {}
578
579impl DoubleEndedIterator for SemicircleFilled<i32> {
580    #[inline]
581    fn next_back(&mut self) -> Option<Self::Item> {
582        if self.x == 0 {
583            return None;
584        }
585
586        loop {
587            let x_tmp = self.x;
588            let y_tmp = self.y;
589            let err_tmp = self.err;
590
591            if err_tmp <= self.y {
592                self.y += 1;
593                self.err += 2 * self.y + 2;
594            };
595
596            if err_tmp > self.x || self.err > self.y {
597                self.x += 1;
598                self.err += 2 * self.x + 2;
599                if self.y == y_tmp {
600                    return Some((-(self.y + 1)..(self.y + 1), (self.x - 1)));
601                }
602            }
603
604            if x_tmp != self.x {
605                let xy = (-self.y..self.y, (self.x - 1));
606
607                return Some(xy);
608            }
609        }
610    }
611}
612
613impl DoubleEndedIterator for SemicircleFilled<i64> {
614    #[inline]
615    fn next_back(&mut self) -> Option<Self::Item> {
616        if self.x == 0 {
617            return None;
618        }
619
620        loop {
621            let x_tmp = self.x;
622            let y_tmp = self.y;
623            let err_tmp = self.err;
624
625            if err_tmp <= self.y {
626                self.y += 1;
627                self.err += 2 * self.y + 2;
628            };
629
630            if err_tmp > self.x || self.err > self.y {
631                self.x += 1;
632                self.err += 2 * self.x + 2;
633                if self.y == y_tmp {
634                    return Some((-(self.y + 1)..(self.y + 1), (self.x - 1)));
635                }
636            }
637
638            if x_tmp != self.x {
639                let xy = (-self.y..self.y, (self.x - 1));
640
641                return Some(xy);
642            }
643        }
644    }
645}
646
647impl DoubleEndedIterator for SemicircleFilled<isize> {
648    #[inline]
649    fn next_back(&mut self) -> Option<Self::Item> {
650        if self.x == 0 {
651            return None;
652        }
653
654        loop {
655            let x_tmp = self.x;
656            let y_tmp = self.y;
657            let err_tmp = self.err;
658
659            if err_tmp <= self.y {
660                self.y += 1;
661                self.err += 2 * self.y + 2;
662            };
663
664            if err_tmp > self.x || self.err > self.y {
665                self.x += 1;
666                self.err += 2 * self.x + 2;
667                if self.y == y_tmp {
668                    return Some((-(self.y + 1)..(self.y + 1), (self.x - 1)));
669                }
670            }
671
672            if x_tmp != self.x {
673                let xy = (-self.y..self.y, (self.x - 1));
674
675                return Some(xy);
676            }
677        }
678    }
679}