use crate::{points_in_circle_unchecked, sum_circles_points_unchecked};
use crate::{Add, FusedIterator, PhantomData, RangeInclusive, Sub};
use crate::{FromAs, Radii, Scaler, Scaling, Zero};
pub trait ConcentricCirclesAdapters: Iterator {
#[inline]
fn add_color<Color>(self, color: Color) -> AddColor<Self, Color>
where
Self: Sized,
{
AddColor { iter: self, color }
}
#[inline]
fn add_color_radial_inclusive<F, Color>(
self,
color: Color,
f: F,
) -> AddColorRadial<Self, F, Color>
where
Self: Sized,
F: FnMut(&mut Color),
{
AddColorRadial {
current_inner_radius: 0,
iter: self,
color,
f,
}
}
#[inline]
fn add_color_radial<F, Color>(self, color: Color, f: F) -> AddColorRadial<Self, F, Color>
where
Self: Radii + Sized,
F: FnMut(&mut Color),
{
AddColorRadial {
current_inner_radius: self.current_inner_radius(),
iter: self,
color,
f,
}
}
#[inline]
fn circle_sector_skip(
mut self,
angle_skip_from: usize,
angle_skip_to: usize,
) -> CircleSectorSkip<Self>
where
Self: Radii + Sized,
{
if angle_skip_from == 0 && angle_skip_to >= 360 {
let _ = self.nth(usize::MAX);
}
if angle_skip_from >= angle_skip_to {
return CircleSectorSkip {
current_circle_points: 0,
iter: self,
take_values: 0,
skip_values: 0,
take_values_iter: (0..=0).scaling(0..=0),
skip_values_iter: (0..=0).scaling(0..=0),
count_returned_values: 1,
};
}
let inner_radius: usize = self.current_inner_radius();
let current_circle_points = points_in_circle_unchecked(inner_radius);
let outer_radius: usize = self.outer_radius();
let mut take_values_iter = scaling_range_take(outer_radius, angle_skip_from);
let mut skip_values_iter = scaling_range_skip(outer_radius, angle_skip_from, angle_skip_to);
if inner_radius > 1 {
let _ = take_values_iter.nth(inner_radius - 2);
let _ = skip_values_iter.nth(inner_radius - 2);
}
CircleSectorSkip {
current_circle_points,
iter: self,
take_values: take_values_iter.next().unwrap_or(0),
skip_values: skip_values_iter.next().unwrap_or(0),
take_values_iter,
skip_values_iter,
count_returned_values: 0,
}
}
#[inline]
fn circle_sector_take(
mut self,
angle_take_from: usize,
angle_take_to: usize,
) -> CircleSectorTake<Self>
where
Self: Radii + Sized,
{
if angle_take_to <= angle_take_from {
let _ = self.nth(usize::MAX);
};
let inner_radius: usize = self.current_inner_radius();
let outer_radius: usize = self.outer_radius();
let mut skip_values_iter = scaling_range_skip_r(outer_radius, angle_take_from);
let mut take_values_iter = scaling_range_take_r(
outer_radius,
if angle_take_to < 360 {
angle_take_to
} else {
360
},
);
if inner_radius > 1 {
let _ = take_values_iter.nth(inner_radius - 2);
let _ = skip_values_iter.nth(inner_radius - 2);
}
CircleSectorTake {
current_circle_points: 0,
iter: self,
take_values: 0,
skip_values: 0,
take_values_iter,
skip_values_iter,
count_returned_values: 0,
}
}
#[inline]
fn crown<U>(self, width: U, height: U) -> Crown<Self, U>
where
Self: Sized + Iterator<Item = (U, U)>,
U: Zero + Sub<Output = U> + PartialOrd + Copy,
{
Crown {
iter: self,
x_bound_min: U::zero(),
y_bound_min: U::zero(),
x_bound_max: width,
y_bound_max: height,
}
}
#[inline]
fn point_with_radius(self) -> PointWithRadius<Self>
where
Self: Sized,
{
PointWithRadius { iter: self }
}
#[inline]
fn step_rings(self, take_value: usize, skip_value: usize) -> StepRings<Self>
where
Self: Radii + Sized,
{
if take_value == 0 {
panic!("take_value must be greater than 0");
}
StepRings {
current_inner_radius: self.current_inner_radius(),
iter: self,
skip_value: skip_value - 1,
take_value,
take_count: 0,
}
}
#[inline]
fn to_image_coordinates<T, U>(self, x_offset: T, y_offset: T) -> ToImageCoordinates<Self, T, U>
where
Self: Sized + Iterator,
{
ToImageCoordinates {
iter: self,
x_offset,
y_offset,
phantom: PhantomData,
}
}
}
#[derive(Debug, Clone)]
pub struct AddColor<I, Color> {
pub(crate) iter: I,
color: Color,
}
impl<I, T, Color> Iterator for AddColor<I, Color>
where
I: Iterator<Item = (T, T)>,
Color: Copy,
{
type Item = (T, T, Color);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (x, y) = self.iter.next()?;
Some((x, y, self.color))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[derive(Debug, Clone)]
pub struct AddColorRadial<I, F, Color> {
pub(crate) iter: I,
color: Color,
f: F,
current_inner_radius: usize,
}
impl<I, T, F, Color> Iterator for AddColorRadial<I, F, Color>
where
I: Iterator<Item = (T, T)> + Radii,
F: FnMut(&mut Color),
Color: Copy,
{
type Item = (T, T, Color);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (x, y) = self.iter.next()?;
let current_inner_radius = self.iter.current_inner_radius();
if self.current_inner_radius != current_inner_radius {
self.current_inner_radius = current_inner_radius;
(self.f)(&mut self.color);
}
Some((x, y, self.color))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[derive(Debug, Clone)]
pub struct CircleSectorSkip<I> {
iter: I,
take_values_iter: Scaling<RangeInclusive<usize>, usize, usize>,
skip_values_iter: Scaling<RangeInclusive<usize>, usize, usize>,
take_values: usize,
skip_values: usize,
current_circle_points: usize,
count_returned_values: usize,
}
impl<I: Default> Default for CircleSectorSkip<I> {
#[inline]
fn default() -> Self {
Self {
iter: Default::default(),
take_values_iter: (0..=0).scaling(0..=0),
skip_values_iter: (0..=0).scaling(0..=0),
take_values: 0,
skip_values: 0,
current_circle_points: 0,
count_returned_values: 0,
}
}
}
impl<I> Iterator for CircleSectorSkip<I>
where
I: Iterator + Radii,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.take_values == self.count_returned_values {
self.current_circle_points =
points_in_circle_unchecked(self.iter.current_inner_radius());
if self.take_values == self.current_circle_points {
self.take_values = self.take_values_iter.next()?;
self.skip_values = self.skip_values_iter.next()?;
if self.take_values == 0 {
let _ = self.iter.nth(self.skip_values - 1);
self.current_circle_points =
points_in_circle_unchecked(self.iter.current_inner_radius());
self.take_values = self.current_circle_points;
self.count_returned_values = self.skip_values;
} else {
self.count_returned_values = 0;
}
} else if self.skip_values == self.current_circle_points {
let _ = self
.iter
.nth(self.current_circle_points - self.take_values - 1);
self.take_values = self.take_values_iter.next()?;
self.skip_values = self.skip_values_iter.next()?;
self.count_returned_values = 0;
} else {
if self.skip_values > self.take_values {
let _ = self.iter.nth(self.skip_values - self.take_values - 1);
}
self.take_values = self.current_circle_points;
self.count_returned_values = self.skip_values;
}
}
self.count_returned_values += 1;
self.iter.next()
}
}
#[derive(Debug, Clone)]
pub struct CircleSectorTake<I> {
iter: I,
take_values_iter: Scaling<RangeInclusive<usize>, usize, usize>,
skip_values_iter: Scaling<RangeInclusive<usize>, usize, usize>,
take_values: usize,
skip_values: usize,
current_circle_points: usize,
count_returned_values: usize,
}
impl<I> Iterator for CircleSectorTake<I>
where
I: Iterator + Radii,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.take_values == self.count_returned_values {
self.skip_values = self.skip_values_iter.next()?;
self.count_returned_values = self.skip_values;
if self.take_values != 0 {
self.current_circle_points =
points_in_circle_unchecked(self.iter.current_inner_radius());
}
self.skip_values += self.current_circle_points - self.take_values;
if self.skip_values != 0 {
let _ = self.iter.nth(self.skip_values - 1);
}
self.take_values = self.take_values_iter.next()?;
}
self.count_returned_values += 1;
self.iter.next()
}
}
#[derive(Clone, Debug)]
pub struct Crown<I: Iterator<Item = (U, U)>, U> {
iter: I,
x_bound_min: U,
y_bound_min: U,
x_bound_max: U,
y_bound_max: U,
}
impl<I, U> Iterator for Crown<I, U>
where
I: Iterator<Item = (U, U)>,
U: PartialOrd + Copy,
{
type Item = (U, U);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
for (x, y) in self.iter.by_ref() {
if x >= self.x_bound_min
&& y >= self.y_bound_min
&& x < self.x_bound_max
&& y < self.y_bound_max
{
return Some((x, y));
}
}
None
}
}
#[derive(Debug, Clone)]
pub struct PointWithRadius<I> {
iter: I,
}
impl<I, T> Iterator for PointWithRadius<I>
where
I: Iterator<Item = (T, T)> + Radii,
{
type Item = (T, T, usize);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let (x, y) = self.iter.next()?;
let r = self.iter.current_inner_radius();
Some((x, y, r))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<I, T> FusedIterator for PointWithRadius<I> where I: Iterator<Item = (T, T)> + Radii {}
#[derive(Debug, Clone)]
pub struct StepRings<I> {
iter: I,
skip_value: usize,
take_value: usize,
take_count: usize,
current_inner_radius: usize,
}
impl<I> Iterator for StepRings<I>
where
I: Iterator + Radii,
{
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let mut xy = self.iter.next()?;
let current_inner_radius = self.iter.current_inner_radius();
if current_inner_radius != self.current_inner_radius {
self.take_count += 1;
if self.take_value == self.take_count {
let skip_circle_points = sum_circles_points_unchecked(
current_inner_radius,
current_inner_radius + self.skip_value,
);
xy = self.iter.nth(skip_circle_points - 1)?;
self.take_count = 0;
}
self.current_inner_radius = self.iter.current_inner_radius();
}
Some(xy)
}
}
#[derive(Clone, Debug)]
pub struct ToImageCoordinates<I, T, U> {
pub(crate) iter: I,
x_offset: T,
y_offset: T,
phantom: PhantomData<U>,
}
impl<I, T, U> Iterator for ToImageCoordinates<I, T, U>
where
I: Iterator<Item = (T, T)>,
T: Add<Output = T> + Copy,
U: FromAs<T> + Copy,
{
type Item = (U, U);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(x, y)| (U::from_as(x + self.x_offset), U::from_as(y + self.y_offset)))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<T: ?Sized> ConcentricCirclesAdapters for T where T: Iterator {}
#[inline]
pub(crate) fn scaling_range_skip(
outer_radius: usize,
angle_take: usize,
angle_skip: usize,
) -> Scaling<RangeInclusive<usize>, usize, usize> {
let circumference = points_in_circle_unchecked(outer_radius);
let angle_correct = match angle_skip {
0 | 45 | 90 | 135 | 180 | 225 | 270 | 315 | 360 => 0,
_ => 1,
};
let (start_skip, end_skip) = match (angle_take, angle_skip) {
(0, 1..=89) => (0, circumference - 1),
(0..=90, 1..=179) => (1, circumference - 1),
(0..=90, 180..=269) => (2, circumference - 1),
(0..=90, 270..=359) => (3, circumference),
(91..=180, 91..=269) => (2, circumference - 1),
(91..=180, 270..=359) => (3, circumference),
(181..=270, 181..=359) => (3, circumference),
(1..=270, 360) => (4, circumference),
(271..=360, 271..=360) => (4, circumference),
(0..360, 0) => (0, 0),
(0, 360) => (0, circumference),
_ => (0, 0),
};
let scaling_range = start_skip
..=(0..=360)
.scaling::<usize>(start_skip..=end_skip)
.nth(angle_skip - angle_correct)
.unwrap_or(0);
(1..=outer_radius).scaling::<usize>(scaling_range)
}
#[inline]
pub(crate) fn scaling_range_take(
outer_radius: usize,
angle_take: usize,
) -> Scaling<RangeInclusive<usize>, usize, usize> {
let circumference = points_in_circle_unchecked(outer_radius);
let angle_correct = match angle_take {
0 | 45 | 90 | 135 | 180 | 225 | 270 | 315 | 360 => 0,
_ => 1,
};
let (start_take, end_take) = match angle_take {
1..=90 => (1, circumference),
91..=180 => (2, circumference - 1),
181..=270 => (3, circumference),
271..=360 => (4, circumference),
_ => (0, 0),
};
let scaling_range = start_take
..=(0..=360)
.scaling::<usize>(start_take..=end_take)
.nth(angle_take - angle_correct)
.unwrap_or(0);
(1..=outer_radius).scaling::<usize>(scaling_range)
}
#[inline]
pub(crate) fn scaling_range_skip_r(
outer_radius: usize,
angle_skip: usize,
) -> Scaling<RangeInclusive<usize>, usize, usize> {
let circumference = points_in_circle_unchecked(outer_radius);
let angle_correct = match angle_skip {
0 | 45 | 90 | 135 | 180 | 225 | 270 | 315 | 360 => 0,
_ => 1,
};
let (start_skip, end_skip) = match angle_skip {
1..=89 => (0, circumference),
90..=179 => (1, circumference - 1),
180..=269 => (2, circumference - 1),
270..=359 => (3, circumference),
360 => (4, circumference),
_ => (0, 0),
};
let scaling_range = start_skip
..=(0..=360)
.scaling::<usize>(start_skip..=end_skip)
.nth(angle_skip - angle_correct)
.unwrap_or(0);
(1..=outer_radius).scaling::<usize>(scaling_range)
}
#[inline]
pub(crate) fn scaling_range_take_r(
outer_radius: usize,
angle_take: usize,
) -> Scaling<RangeInclusive<usize>, usize, usize> {
let circumference = points_in_circle_unchecked(outer_radius);
let angle_correct = match angle_take {
0 | 45 | 90 | 135 | 180 | 225 | 270 | 315 | 360 => 0,
_ => 1,
};
let (start_take, end_take) = match angle_take {
1..=90 => (1, circumference),
91..=180 => (2, circumference - 1),
181..=270 => (3, circumference),
271..=360 => (4, circumference),
_ => (0, 0),
};
let scaling_range = start_take
..=(0..=360)
.scaling::<usize>(start_take..=end_take)
.nth(angle_take - angle_correct)
.unwrap_or(0);
(1..=outer_radius).scaling::<usize>(scaling_range)
}