wallswitch 0.60.8

randomly selects wallpapers for multiple monitors
Documentation
//! Julia Set fractal generator overlay.
//!
//! This module provides the implementation of the Julia Set fractal renderer,
//! using pre-programmed coordinate presets. It generates mathematical overlays
//! dynamically fitted to the display dimensions and blends them using high-contrast
//! dual-tone chromatic borders and 3D shadow depth offsets.

use crate::effects::{
    FractalPreset, MAX_ITERATIONS, MIN_ITERATIONS, ProceduralEffect, color_distance_estimator,
    compute_escape_iterations, find_optimal_framing, render_fractal_parallel,
};
use crate::{Complex, ImageEffect, NEON_PALETTES, NeonColor, get_random_integer};
use image::RgbImage;

/// A procedural generator for rendering Julia Set fractals onto desktop backgrounds.
///
/// Combines mathematical coordinate presets with viewport fitting, lighting shaders,
/// and color interpolation to produce high-definition digital art overlays.
///
/// # Mathematical Foundation
/// The Julia Set is computed by mapping viewport coordinates z_0 in complex space under
/// the quadratic recurrence relation:
///
/// z_(n+1) = f(z_n) = z_n^2 + c
///
/// Where the perturbation parameter c is a constant determined by the preset.
/// Points are classified as escaping if at any step n, the magnitude of z_n is greater than 2.
pub struct JuliaGenerator {
    /// The active coordinate preset, enclosing the center points and metadata.
    pub preset: FractalPreset,
    /// The maximum iteration limit for escape-time calculations.
    pub scan_iterations: u32,
    /// The base color palette selected for the neon glow.
    pub color_palette: NeonColor,
    /// The viewport zoom level.
    pub zoom: f64,
    /// The cosine of the rotation angle.
    pub cos_angle: f64,
    /// The sine of the rotation angle.
    pub sin_angle: f64,
}

impl Default for JuliaGenerator {
    /// Returns the default fallback instance of the Julia Set generator.
    fn default() -> Self {
        Self {
            preset: FractalPreset {
                center: Complex::new(-0.7, 0.27015),
                fractal_name: "Classic dendrite",
                effect_name: ProceduralEffect::JuliaSet,
            },
            scan_iterations: get_random_integer(MIN_ITERATIONS, MAX_ITERATIONS),
            color_palette: NEON_PALETTES[5],
            zoom: 3.0,
            cos_angle: 1.0,
            sin_angle: 0.0,
        }
    }
}

/// Implementation of the [`ImageEffect`] trait for rendering Julia Set fractals.
impl ImageEffect for JuliaGenerator {
    /// Applies the Julia Set procedural overlay onto an in-memory image buffer.
    fn apply(&self, rgb_img: &mut RgbImage) {
        let center = self.preset.center;
        let scan_iterations = self.scan_iterations;
        let color_palette = self.color_palette;

        render_fractal_parallel(
            rgb_img,
            self.zoom,
            self.cos_angle,
            self.sin_angle,
            center,
            true,
            |z_init, scale| {
                let (i, z, dz) = compute_escape_iterations(
                    ProceduralEffect::JuliaSet,
                    z_init,
                    center,
                    scan_iterations,
                );

                color_distance_estimator(i, scan_iterations, z, dz, scale, color_palette)
            },
        );
    }

    /// Returns formatting diagnostic information about the active generator.
    fn info(&self) -> String {
        format!(
            "fractal [{}]\n\
            f(z) = z^2 + c, where c = {:8.5} {} {:7.5}i (iter = {:4}, zoom = {:.2}), color: {}",
            self.preset.fractal_name,
            self.preset.center.re,
            if self.preset.center.im >= 0.0 {
                "+"
            } else {
                "-"
            },
            self.preset.center.im.abs(),
            self.scan_iterations,
            self.zoom,
            self.color_palette
        )
    }
}

impl JuliaGenerator {
    /// Generates a randomized Julia Set configuration fitted to the target aspect ratio.
    ///
    /// Selects one of the built-in coordinate presets, assigns a neon color palette,
    /// rotates the coordinate system randomly, and optimizes the viewport fit.
    pub fn random(monitor: &crate::Monitor) -> Self {
        let width = monitor.resolution.width as u32;
        let height = monitor.resolution.height as u32;

        let presets = [
            FractalPreset {
                center: Complex::new(-0.4, 0.6),
                fractal_name: "Classic cloud swirls",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.8, 0.156),
                fractal_name: "Detailed spirals",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.7269, 0.1889),
                fractal_name: "Lace structures",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.75, 0.11),
                fractal_name: "Feathery branches",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.1, 0.651),
                fractal_name: "Cosmic dust style",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(0.355, 0.355),
                fractal_name: "Spiral galaxy arms",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.4, -0.59),
                fractal_name: "Swirling vortexes",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.54, 0.54),
                fractal_name: "Ornamental lace borders",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.835, -0.2321),
                fractal_name: "Lightning rods",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.77269, 0.12428),
                fractal_name: "Coral reefs",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.51251, 0.5213),
                fractal_name: "Fine lace filaments",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.55, 0.55),
                fractal_name: "Intricate leaf outlines",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.624, 0.435),
                fractal_name: "Crystalline snowflake patterns",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.12, 0.85),
                fractal_name: "Flowing plasma plumes",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.391, -0.587),
                fractal_name: "Swirling storm clouds",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.73, 0.21),
                fractal_name: "Feathery dendritic lace",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.81, 0.2),
                fractal_name: "Spiral galaxy filaments",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.68, 0.34),
                fractal_name: "Delicate coral spirals",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.76, 0.08),
                fractal_name: "Lightning tree branches",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(0.285, 0.01),
                fractal_name: "Cosmic galaxy vortex swirls",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.8, 0.17),
                fractal_name: "Spidery lace denderites",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.7269, -0.1889),
                fractal_name: "Conjugate lace structures",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.835, 0.2321),
                fractal_name: "Conjugate lightning rods",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.75, 0.05),
                fractal_name: "Dense branching coral reef",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.70176, 0.3842),
                fractal_name: "Conjugate dragon-like curves",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.8, 0.16),
                fractal_name: "Deep sea coral spirals",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.722, 0.246),
                fractal_name: "Dendritic pine branch variation",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.11, 0.655),
                fractal_name: "Triple helix rotational cosmic swirls",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.52519, 0.5215),
                fractal_name: "Intertwined Gothic Cathedral window arches",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(0.28, 0.008),
                fractal_name: "Centrifugal pinwheel galaxy vortex generator",
                effect_name: ProceduralEffect::JuliaSet,
            },
            FractalPreset {
                center: Complex::new(-0.83, -0.232),
                fractal_name: "Sharp crystalline glacial ice column needles",
                effect_name: ProceduralEffect::JuliaSet,
            },
        ];

        let p_idx: usize = get_random_integer(0, NEON_PALETTES.len() - 1);
        let color_palette = NEON_PALETTES[p_idx];

        let angle_degrees: f64 = get_random_integer(0, 359);
        let radians = angle_degrees.to_radians();

        let preset_idx: usize = get_random_integer(0, presets.len() - 1);
        let selected_preset = presets[preset_idx];

        let mut julia = Self {
            preset: selected_preset,
            scan_iterations: get_random_integer(MIN_ITERATIONS, MAX_ITERATIONS),
            color_palette,
            zoom: 3.0,
            cos_angle: radians.cos(),
            sin_angle: radians.sin(),
        };

        julia.optimize_fit(width, height);
        julia
    }

    /// Optimizes the viewport boundaries by scanning complex boundaries and finding a balanced zoom.
    ///
    /// Preserves exact spatial conformality during search limits calculation.
    pub fn optimize_fit(&mut self, width: u32, height: u32) {
        let c_abs = self.preset.center.norm_sq().sqrt();
        let r_bound = (1.0 + (1.0 + 4.0 * c_abs).sqrt()) / 2.0;
        let search_limit = r_bound * 1.2;

        let steps = 128;
        let inv_steps_minus_1 = 1.0 / (steps - 1) as f64;
        let range = 2.0 * search_limit;

        let scan_iterations = self.scan_iterations;
        let mut active_points = Vec::with_capacity(steps * steps / 2);

        for step_y in 0..steps {
            let ry = -search_limit + (step_y as f64 * inv_steps_minus_1) * range;
            for step_x in 0..steps {
                let rx = -search_limit + (step_x as f64 * inv_steps_minus_1) * range;

                let (i, _, _) = compute_escape_iterations(
                    ProceduralEffect::JuliaSet,
                    Complex::new(rx, ry),
                    self.preset.center,
                    scan_iterations,
                );

                if i > 3 && i < scan_iterations {
                    active_points.push(Complex::new(rx, ry));
                }
            }
        }

        if !active_points.is_empty() {
            let (best_zoom, best_cos, best_sin) = find_optimal_framing(
                &active_points,
                width,
                height,
                self.cos_angle,
                self.sin_angle,
            );
            self.zoom = best_zoom * 1.10;
            self.cos_angle = best_cos;
            self.sin_angle = best_sin;
        } else {
            self.zoom = 2.0 * r_bound * 1.10;
        }
    }
}

#[cfg(test)]
mod tests_julia {
    use super::*;
    use crate::core::Monitor;

    #[test]
    fn test_julia_generation_random() {
        let monitor = Monitor::default();
        let julia = JuliaGenerator::random(&monitor);
        assert!(julia.zoom > 0.0);
        assert_eq!(julia.preset.effect_name, ProceduralEffect::JuliaSet);
    }
}