Implement basic variation support
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
//! # Variation
|
||||
|
||||
use crate::Coefficients2;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use core::f32::consts::PI;
|
||||
use glam::{Affine2, Vec2, vec2};
|
||||
use libm::{atan2f, cosf, powf, sinf, sqrtf, tanf};
|
||||
use rand::distr::Bernoulli;
|
||||
use rand::{Rng, RngExt};
|
||||
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct VariationParams([f32; 4]);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u32)]
|
||||
pub enum VariationKind {
|
||||
Linear = 0,
|
||||
Julia = 13,
|
||||
Popcorn = 17,
|
||||
Pdj = 24,
|
||||
}
|
||||
|
||||
// UNSAFE: Sound because enum has guaranteed layout (u32) and defined zero-value
|
||||
unsafe impl bytemuck::Zeroable for VariationKind {}
|
||||
// UNSAFE: Sound because enum has guaranteed layout (u32) and defined zero-value
|
||||
unsafe impl bytemuck::Pod for VariationKind {}
|
||||
|
||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct Variation {
|
||||
kind: VariationKind,
|
||||
weight: f32,
|
||||
params: VariationParams,
|
||||
}
|
||||
|
||||
impl Variation {
|
||||
pub fn transform_point<R: Rng>(
|
||||
&self,
|
||||
point: Vec2,
|
||||
rng: &mut R,
|
||||
coefficients: &Affine2,
|
||||
) -> Vec2 {
|
||||
(match self.kind {
|
||||
VariationKind::Linear => transform_point_linear(point),
|
||||
VariationKind::Julia => transform_point_julia(point, rng),
|
||||
VariationKind::Popcorn => transform_point_popcorn(point, coefficients),
|
||||
VariationKind::Pdj => transform_point_pdj(point, &self.params),
|
||||
}) * self.weight
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_point_linear(point: Vec2) -> Vec2 {
|
||||
point
|
||||
}
|
||||
|
||||
fn transform_point_julia<R: Rng>(point: Vec2, rng: &mut R) -> Vec2 {
|
||||
let x2 = powf(point.x, 2.0);
|
||||
let y2 = powf(point.y, 2.0);
|
||||
let r = sqrtf(x2 + y2);
|
||||
|
||||
let theta = atan2f(point.x, point.y);
|
||||
let omega_choice = rng.sample(Bernoulli::new(0.5).unwrap());
|
||||
let omega = if omega_choice { PI } else { 0.0 };
|
||||
|
||||
let sqrt_r = sqrtf(r);
|
||||
let theta_val = theta / 2.0 + omega;
|
||||
|
||||
vec2(sqrt_r * cosf(theta_val), sqrt_r * sinf(theta_val))
|
||||
}
|
||||
|
||||
fn transform_point_popcorn(point: Vec2, coefficients: &Affine2) -> Vec2 {
|
||||
vec2(
|
||||
point.x * coefficients.c() * sinf(tanf(3.0 * point.y)),
|
||||
point.y + coefficients.f() * sinf(tanf(3.0 * point.x)),
|
||||
)
|
||||
}
|
||||
|
||||
fn transform_point_pdj(point: Vec2, params: &VariationParams) -> Vec2 {
|
||||
let (pdj_a, pdj_b, pdj_c, pdj_d) = (params.0[0], params.0[1], params.0[2], params.0[3]);
|
||||
vec2(
|
||||
sinf(pdj_a * point.y) - cosf(pdj_b * point.x),
|
||||
sinf(pdj_c * point.x) - cosf(pdj_d * point.y),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user