summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 0e1e5fff3d758375273d185f2bfe6e566fd1d423 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
extern crate rand;
extern crate num_complex;
extern crate png;

use std::io;
use num_complex::Complex;

//stuff for PNG output
use std::path::Path;
use std::fs::File;
use std::io::BufWriter;
// To use encoder.set()
use png::HasParameters;

use std::cmp;

use rand::distributions::{IndependentSample, Range};

struct Trajectory
{
	length : usize,
	offset : Complex<f64>,
	iteration: usize,
	current : Complex<f64>,
    points : Vec<Complex<f64>>
}

struct Pixel
{
	r : u32,
	g : u32,
	b : u32,
	a : u32
}

impl Trajectory {
    fn new(length : usize, offset : Complex<f64>) -> Trajectory {
        Trajectory{length : length, offset : offset, iteration : 0, current : Complex::new(0.0,0.0), points : Vec::with_capacity(length)}
    }

    fn is_done(&self) -> bool{
        self.length == self.iteration+1
    }

    fn advance(&mut self) -> bool {
        if self.is_done(){
	        return false;
        }
        self.iteration = self.iteration+1;
        self.current = self.current * self.current + self.offset;
        self.points.push(self.current);
        return !self.is_done();
    }

    fn run(&mut self, bailout : f64){
        let mut done = false;
     	while !done{
            done = done || !self.advance();
	        if self.current.norm_sqr() > bailout*bailout {
      	        done = true
	        }
	    }
    }
}

fn write_png(filename : &str, pixels : &Vec<Pixel>, max_cnt : u32, width : u32, height : u32){
    let mut png_data : Vec<u8> = Vec::with_capacity(pixels.len()*4);
    for pix in pixels.iter()
    {
        png_data.push(((pix.r*255)/max_cnt) as u8);
        png_data.push(((pix.g*255)/max_cnt) as u8);
        png_data.push(((pix.b*255)/max_cnt) as u8);
        //png_data.push(((pix.a*255)/max_cnt) as u8); //nope, a will not be normalized
        png_data.push(255);
    }

    let path = Path::new(filename);
    let file = File::create(path).unwrap();
    let ref mut w = BufWriter::new(file);

    let mut encoder = png::Encoder::new(w, width, height); 
    encoder.set(png::ColorType::RGBA).set(png::BitDepth::Eight);
    let mut writer = encoder.write_header().unwrap();

    writer.write_image_data(&png_data.as_slice()).unwrap(); // Save
}

fn get_pixel(path_point : &Complex<f64>, width : i32, height : i32) -> i32{
    if path_point.re < -2.5 || path_point.re > 1.0 || path_point.im < -1.0  || path_point.im > 1.0 {
        return -1;
    }
    let x_index = ((width as f64) * ((path_point.re + 2.5)/3.5)) as i32;
    let y_index = ((height as f64) * ((path_point.im + 1.0)/2.0)) as i32;
    return x_index + y_index*width;
}


fn main() {

    let x = 1920;
    let y = 1080;

    let trajectory_count = 1000000;
    let path_length = 10000;

    let bailout = 50.0;

    //arrays would do, if we knew size at compile time. We do right now, but we want them tweakable later on
    let mut workspace = Vec::with_capacity(x*y);
    for _number in 0..x*y {
        workspace.push(Pixel{r:0, g:0, b:0,a:1});
    }


    let mut max_cnt = 1;

    let x_range = Range::new(-2.5,1.0);
    let y_range = Range::new(-1.0,1.0);
    let mut rng = rand::thread_rng();


    for _traj in 0..trajectory_count {
        let offset = Complex::new(x_range.ind_sample(&mut rng),y_range.ind_sample(&mut rng));
        let mut traj = Trajectory::new(path_length,offset);
        traj.run(bailout);
        if traj.current.norm_sqr() < bailout*bailout {
            continue;
        }

        for point in traj.points{
            let mirror_point = point.conj();
            let pix = [get_pixel(&point, x as i32, y as i32),get_pixel(&mirror_point, x as i32, y as i32)];
            if pix[0] < 0 || pix[1] < 0 {
                continue;
            }
            
            for index in pix.iter() {
                let mut item = &mut workspace[*index as usize];
                item.r = item.r + 1;
                item.g = item.g + 1;
                item.b = item.g + 1;
                max_cnt = cmp::max(cmp::max(max_cnt,item.b),cmp::max(item.r,item.g));
            }
        }
     
    }



    write_png(r"image.png",&workspace, max_cnt,x as u32,y as u32);
}