#[cfg(feature = "vec")]
use svg::node::element;
#[cfg(any(feature = "vec", feature = "pix"))]
use crate::colors::Color;
#[cfg(feature = "pix")]
#[derive(Clone, Copy, Debug, PartialEq)]
struct Circle {
x_center: f32,
y_center: f32,
radius: f32,
rgba_color: Color,
}
#[cfg(feature = "pix")]
fn in_circle(x: i32, y: i32, circle: &Circle) -> bool {
(x as f32 - circle.x_center).powi(2) + (y as f32 - circle.y_center).powi(2)
< circle.radius.powi(2)
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CirclePosition {
pub x_center: f32,
pub y_center: f32,
}
pub fn position_circle_set(center_to_center: f32) -> [CirclePosition; 19] {
let a = center_to_center;
let b = center_to_center * 3f32.sqrt() / 2f32;
[
CirclePosition {
x_center: 0f32,
y_center: -2f32 * a,
},
CirclePosition {
x_center: 0f32,
y_center: -a,
},
CirclePosition {
x_center: -b,
y_center: -3f32 * a / 2f32,
},
CirclePosition {
x_center: -2f32 * b,
y_center: -a,
},
CirclePosition {
x_center: -b,
y_center: -a / 2f32,
},
CirclePosition {
x_center: -2f32 * b,
y_center: 0f32,
},
CirclePosition {
x_center: -2f32 * b,
y_center: a,
},
CirclePosition {
x_center: -b,
y_center: a / 2f32,
},
CirclePosition {
x_center: -b,
y_center: 3f32 * a / 2f32,
},
CirclePosition {
x_center: 0f32,
y_center: 2f32 * a,
},
CirclePosition {
x_center: 0f32,
y_center: a,
},
CirclePosition {
x_center: b,
y_center: 3f32 * a / 2f32,
},
CirclePosition {
x_center: 2f32 * b,
y_center: a,
},
CirclePosition {
x_center: b,
y_center: a / 2f32,
},
CirclePosition {
x_center: 2f32 * b,
y_center: 0f32,
},
CirclePosition {
x_center: 2f32 * b,
y_center: -a,
},
CirclePosition {
x_center: b,
y_center: -a / 2f32,
},
CirclePosition {
x_center: b,
y_center: -3f32 * a / 2f32,
},
CirclePosition {
x_center: 0f32,
y_center: 0f32,
},
]
}
#[cfg(feature = "pix")]
fn get_colored_circles(
center_to_center: f32,
small_radius: f32,
colors: [Color; 19],
) -> [Circle; 19] {
let positions = position_circle_set(center_to_center);
let mut out: Vec<Circle> = Vec::with_capacity(19);
for (i, position) in positions.iter().enumerate() {
let new = Circle {
x_center: position.x_center,
y_center: position.y_center,
radius: small_radius,
rgba_color: colors[i],
};
out.push(new);
}
out.try_into().expect("always generate 19-element set")
}
#[cfg(feature = "pix")]
pub fn calculate_png_data(size_in_pixels: u16, colors: [Color; 19]) -> Vec<u8> {
let mut data: Vec<u8> = Vec::new();
let big_radius = size_in_pixels as f32 / 2f32;
let small_radius = big_radius / 32f32 * 5f32;
let center_to_center = big_radius / 8f32 * 3f32;
let big_circle = Circle {
x_center: 0f32,
y_center: 0f32,
radius: big_radius,
rgba_color: Color::foreground(),
};
let small_circles_set = get_colored_circles(center_to_center, small_radius, colors);
let iter_start = -(size_in_pixels as i32) / 2;
let iter_end = { (size_in_pixels >> 1) + (size_in_pixels & 0x01) } as i32;
for y in iter_start..iter_end {
for x in iter_start..iter_end {
if in_circle(x, y, &big_circle) {
let mut some_small_circle = None;
for cir in small_circles_set.iter() {
if in_circle(x, y, cir) {
some_small_circle = Some(cir.rgba_color);
break;
}
}
match some_small_circle {
Some(color) => data.extend_from_slice(&color.to_array()),
None => data.extend_from_slice(&big_circle.rgba_color.to_array()),
}
} else {
data.extend_from_slice(&Color::background().to_array())
}
}
}
data
}
#[cfg(feature = "vec")]
pub fn calculate_svg_data(big_radius: f32, colors: [Color; 19]) -> Vec<element::Circle> {
let mut out: Vec<element::Circle> = Vec::with_capacity(20);
out.push(
element::Circle::new()
.set("cx", 0f32)
.set("cy", 0f32)
.set("r", big_radius)
.set("fill", Color::foreground().to_hex())
.set("stroke", "none"),
);
let small_radius = big_radius / 32f32 * 5f32;
let center_to_center = big_radius / 8f32 * 3f32;
let positions = position_circle_set(center_to_center);
for (i, position) in positions.iter().enumerate() {
out.push(
element::Circle::new()
.set("cx", position.x_center)
.set("cy", position.y_center)
.set("r", small_radius)
.set("fill", colors[i].to_hex())
.set("stroke", "none"),
);
}
out
}