4
\$\begingroup\$

Among the many fractals, there is Collatz Fractal based on a complex extension of: $$f(x) = \left\{ \begin{array}{ll} \frac{x}{2} \space \text{if even} \\ 3x + 1 \space \text{if odd} \end{array} \right.$$

To generate the fractal, you pick a bunch of points and repeatedly apply f over and over again a large number of times. Morally, f(f(f(f(....f(x)....)))) In this case, however, it is not a real number x but instead a complex number (often denoted z). The end result is plotted by giving it a color that "corresponds" to the size of the result.

The resulting image is:

Collatz Fractal

Here is the code:

lib.rs

/// A fractal generation module.
pub mod fractal_gen {
    extern crate image;
    extern crate num_complex;

    use self::num_complex::Complex;
    use std;

    /// Complex extension of the Collatz function.
    ///
    /// # Arguments
    /// * `z` - A complex number.
    ///
    /// # Returns
    /// * The Collatz function applied to `z`. Where the Collatz function foll-
    /// ows the definition from here: http://yozh.org/2012/01/12/the_collatz_fractal/
    pub fn collatz(z: Complex<f32>) -> Complex<f32> {
        let comp_pi = Complex::new(std::f32::consts::PI, 0.0);
        return ((7.0 * z + 2.0) 
             - (comp_pi * z).cos() 
             * (5.0 * z + 2.0)) / 4.0;
    }

    /// Generate a fractal picture.
    ///
    /// # Arguments
    /// * `buf` - Image buffer that will store the result image.
    /// * `f` - Complex function that returns a complex number.
    /// * `scalex` - Horizontal scaling factor.
    /// * `scaley` - Vertical scaling factor.
    /// * `max_iterations` - Maximum number of applications of `f`.
    pub fn populate_image(buf: &mut image::GrayImage, 
                      f: fn(Complex<f32>) -> Complex<f32>,
                      scalex: f32, scaley: f32,
                      max_iterations: u16) {
        for (x, y, pixel) in buf.enumerate_pixels_mut() {
            let cy = y as f32 * scaley - 2.0;
            let cx = x as f32 * scalex - 2.0;

            let mut z = Complex::new(cx, cy);

            let mut i = 0;

            for t in 0..max_iterations {
                if z.norm() > 1000.0 {
                    break
                }
                z = f(z);
                i = t;
            }
            *pixel = image::Luma([i as u8]);
        }
    }
}

main.rs

extern crate fraclib;
extern crate argparse;
extern crate image;

use argparse::{ArgumentParser, Store};
use fraclib::fractal_gen;

/// Generates and exports a fractal.png. fractal.png is a picture of the Colla-
/// tz fractal.
///
/// # Flags
///
/// * `--maxiter` iteration depth for successive iteration on the Collatz func-
/// tion.
/// * `--xdim` width of the image.
/// * `--ydim` height of the image.
/// * `--scalewidth` horizontal scaling factor.
/// * `--scaleheight` vertical scaling factor.
fn main() {
    let mut max_iterations = 1024u16;

    let mut imgx = 800;
    let mut imgy = 800;

    let mut scalex = 4.0 / imgx as f32;
    let mut scaley = 4.0 / imgy as f32;

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Create a Collatz Fractal.");
        ap.refer(&mut max_iterations)
            .add_option(&["-i", "--maxiter"], Store,
            "Maximum number of iterations on Collatz function");
        ap.refer(&mut imgx)
            .add_option(&["-x", "--xdim"], Store,
            "The x dimension of the generated image");
        ap.refer(&mut imgy)
            .add_option(&["-y", "--ydim"], Store,
            "The y dimension of the generated image");
        ap.refer(&mut scalex)
            .add_option(&["-w", "--scalewidth"], Store,
            "The width scaling factor");
        ap.refer(&mut scaley)
            .add_option(&["-h", "--scaleheight"], Store,
            "The height scaling factor");
        ap.parse_args_or_exit();
    }

    let mut imgbuf = image::GrayImage::new(imgx, imgy);

    fractal_gen::populate_image(&mut imgbuf, 
                                fractal_gen::collatz,
                                scalex, scaley,
                                max_iterations);

    // Save the image as “fractal.png”, the format is deduced from the path
    imgbuf.save("fractal.png").unwrap();
}

Github can be found here. Heavily modified variant of the Mandelbrot example given here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.