DEV Community

Antonio Perrone
Antonio Perrone

Posted on

A Weekly Rust🦀 Pill #3

A Weekly Rust🦀 Pill is a post series where on a weekly base, I share some implementations of the most popular algorithms and data structures to share my learnings on Rust 🦀.

What is the Mandelbrot Set?

The Mandelbrot Set is a set of complex numbers defined by iterating a simple mathematical formula. Given a complex number c, we start with an initial value of z (typically set to 0) and then repeatedly apply the formula z = z * z + c. If the value of z diverges to infinity (i.e., its magnitude exceeds a certain threshold), the complex number z is not part of the Mandelbrot Set. Otherwise, it is considered part of the set. The points that belong to the set are coloured distinctly, forming the breathtaking fractal pattern we all recognise.

Implementation

Once you have Rust set up, create a new Rust project and add the required dependencies to your Cargo.toml:

[dependencies]
image = "0.24.1"
nalgebra = "0.24.1"
Enter fullscreen mode Exit fullscreen mode

The image crate will help us save the generated image of the Mandelbrot Set, while nalgebra will provide the necessary complex number functionality.

Let's start by defining the function to determine if a given complex number 'c' belongs to the Mandelbrot Set. We'll call this function mandelbrot:

use nalgebra::{Complex, Normed};

fn mandelbrot(x: f64, y: f64) -> u8 {
    let c = Complex::new(x, y);
    let mut z = Complex::new(0.0, 0.0);

    for i in 0..255 {
        if z.norm() > 2.0 {
            return i as u8;
        }

        z = z * z + c;
    }

    255
}
Enter fullscreen mode Exit fullscreen mode

The mandelbrot function takes two coordinates, 'x' and 'y', as inputs and returns a color value represented by a u8. The function uses the 'x' and 'y' values to create a complex number 'c'. It then iterates the formula 'z = z * z + c' until the magnitude of 'z' exceeds 2.0 or until the maximum number of iterations (255) is reached. The colour value returned represents how quickly the sequence diverges to infinity.

Now that we have the mandelbrot function, let's visualise the Mandelbrot Set using the image crate. We'll define a function called generate_mandelbrot_set to create and save the image:

use image::{ImageBuffer, Rgb};

fn generate_mandelbrot_set(width: u32, height: u32) {
    let scale_x = 3.0 / width as f64;
    let scale_y = 3.0 / height as f64;

    let mut img = ImageBuffer::new(width, height);

    for (x, y, pixel) in img.enumerate_pixels_mut() {
        let r = (0.3 * x as f32) as u8;
        let b = (0.3 * y as f32) as u8;
        *pixel = image::Rgb([r, 0, b]);

        let cx = x as f64 * scale_x - 2.0;
        let cy = y as f64 * scale_y - 1.5;

        let value = mandelbrot(cx as f64, cy as f64);

        *pixel = Rgb([r, value, b]);
    }

    let _ = img.save("mandelbrot.png");
}
Enter fullscreen mode Exit fullscreen mode

The generate_mandelbrot_set function takes the width and height of the image as inputs and proceeds to generate the Mandelbrot Set visualization. It creates a blank image of the specified dimensions and then iterates over each pixel, calculating the corresponding complex number 'c' using the pixel coordinates. The mandelbrot function is called to determine the color value for that pixel, and the resulting color is assigned to the pixel.

The colors of the pixels are based on the 'r' (red) and 'b' (blue) values, with the green channel set to the computed color value from the mandelbrot function. The result is an aesthetically pleasing and captivating visualization of the Mandelbrot Set.

References

Top comments (0)