use crate::define_param;
use crate::pattern::params::{ParamType, PatternParam};
use std::any::Any;
use std::f64::consts::PI;
define_param!(num Diagonal, AngleParam, "angle", "Angle of the diagonal pattern", 0.0, 360.0, 45.0);
define_param!(num Diagonal, FrequencyParam, "frequency", "Animation speed", 0.1, 10.0, 1.0);
#[derive(Debug, Clone)]
pub struct DiagonalParams {
pub angle: i32,
pub frequency: f64,
}
impl DiagonalParams {
const ANGLE_PARAM: DiagonalAngleParam = DiagonalAngleParam;
const FREQUENCY_PARAM: DiagonalFrequencyParam = DiagonalFrequencyParam;
}
impl Default for DiagonalParams {
fn default() -> Self {
Self {
angle: 45,
frequency: 1.0,
}
}
}
define_param!(validate DiagonalParams,
ANGLE_PARAM: DiagonalAngleParam,
FREQUENCY_PARAM: DiagonalFrequencyParam
);
impl PatternParam for DiagonalParams {
fn name(&self) -> &'static str {
"diagonal"
}
fn description(&self) -> &'static str {
"Gradient at an angle with wave animation"
}
fn param_type(&self) -> ParamType {
ParamType::Composite
}
fn default_value(&self) -> String {
format!("angle={},frequency={}", self.angle, self.frequency)
}
fn validate(&self, value: &str) -> Result<(), String> {
self.validate_params(value)
}
fn parse(&self, value: &str) -> Result<Box<dyn PatternParam>, String> {
let mut params = DiagonalParams::default();
for part in value.split(',') {
let kv: Vec<&str> = part.split('=').collect();
if kv.len() != 2 {
continue;
}
match kv[0] {
"angle" => {
Self::ANGLE_PARAM.validate(kv[1])?;
params.angle = kv[1].parse().unwrap();
}
"frequency" => {
Self::FREQUENCY_PARAM.validate(kv[1])?;
params.frequency = kv[1].parse().unwrap();
}
invalid_param => {
return Err(format!("Invalid parameter name: {}", invalid_param));
}
}
}
Ok(Box::new(params))
}
fn sub_params(&self) -> Vec<Box<dyn PatternParam>> {
vec![Box::new(Self::ANGLE_PARAM), Box::new(Self::FREQUENCY_PARAM)]
}
fn clone_param(&self) -> Box<dyn PatternParam> {
Box::new(self.clone())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl super::Patterns {
#[inline(always)]
pub fn diagonal(&self, x_norm: f64, y_norm: f64, params: DiagonalParams) -> f64 {
let angle_rad = params.angle as f64 * (PI / 180.0);
#[allow(non_snake_case)]
let (sinA, cosA) = {
let sin_val = self.utils.fast_sin(angle_rad);
let cos_val = self.utils.fast_cos(angle_rad);
(sin_val, cos_val)
};
let pos = (x_norm + 0.5) * cosA + (y_norm + 0.5) * sinA;
let mut value = pos + self.time * params.frequency;
value -= value.floor();
value
}
}