mirror of
https://github.com/Noratrieb/mandelbrot-rust.git
synced 2026-01-14 23:35:03 +01:00
initial commit
This commit is contained in:
parent
7577fc6041
commit
764d2ff644
3 changed files with 308 additions and 25 deletions
213
src/MandelbrotSet.java
Normal file
213
src/MandelbrotSet.java
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class MandelbrotSet {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
double progress = 0;
|
||||
double amount;
|
||||
|
||||
// I think there might be some stuff mixed up in the code but it works
|
||||
// not sure though
|
||||
|
||||
double[][] interestingPoints = { { -0.75, 0 }, { -0.77568377, 0.13646737 } };
|
||||
|
||||
// important settings-------------------------------------------------------------
|
||||
int pointNumber = 1;
|
||||
int quality = 2; // 0 = very low, 1 = low, 2 = medium, 3 = high, 4 = ultra, any number bigger than 5 = custom
|
||||
double zoomSpeed = 1.1; // >1
|
||||
int frames = 100;
|
||||
int width = 1920;
|
||||
//................................................................................
|
||||
|
||||
// less important settings
|
||||
boolean advancedIndicators = true;
|
||||
double forceCenterX = interestingPoints[pointNumber][0];
|
||||
double forceCenterY = interestingPoints[pointNumber][1];
|
||||
boolean imageMode = true;
|
||||
int height = 1080;
|
||||
boolean locked = true;
|
||||
float ratio = 2 / 3f; // .2 for editor 2/3 for image
|
||||
double zoom = 1;
|
||||
int iterations;
|
||||
double threshold = 100;
|
||||
char low = ' ';
|
||||
char high = '#';
|
||||
|
||||
if (quality == 0) {
|
||||
iterations = 20;
|
||||
} else if (quality == 1) {
|
||||
iterations = 50;
|
||||
} else if (quality == 2) {
|
||||
iterations = 100;
|
||||
} else if (quality == 3) {
|
||||
iterations = 500;
|
||||
} else if (quality == 4) {
|
||||
iterations = 1000;
|
||||
} else {
|
||||
iterations = quality;
|
||||
}
|
||||
|
||||
double offsetX;
|
||||
double offsetY;
|
||||
if (locked) {
|
||||
height = (int) ((float) width * ratio);
|
||||
}
|
||||
|
||||
// TIME
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
for (int frameCounter = 0; frameCounter < frames; frameCounter++) {
|
||||
// progress = 0;
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
File f = null;
|
||||
|
||||
// the printed image is 3 * 2 (from x = -3 to x = 1 and
|
||||
double stepSizeX = (3 / (float) width) / zoom;
|
||||
double stepSizeY = (2 / (float) height) / zoom;
|
||||
|
||||
offsetX = forceCenterX - width / 2 * stepSizeX;
|
||||
offsetY = -(forceCenterY - height / 2 * stepSizeY);
|
||||
|
||||
// calculate coords using stepSize and hardcoded corner coords:
|
||||
// create an array of complex numbers, where the position of each sample will be stored
|
||||
CNumber[][] coords = new CNumber[width][height];
|
||||
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
coords[i][j] = new CNumber(); // fill the array
|
||||
coords[i][j].real = offsetX + stepSizeX * i; // calculate the position on the real numberline
|
||||
coords[i][j].imag = offsetY - stepSizeY * j; // calculate the position on the imaginary numberline
|
||||
}
|
||||
}
|
||||
|
||||
// calculate values
|
||||
double[][] values = new double[width][height]; // new array of booleans for the drawing
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
values[i][j] = checkMandelbrot(coords[i][j], iterations, threshold); // check if the number is inside of th set
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (imageMode) {
|
||||
|
||||
createImage(image, frameCounter, f, width, height, values);
|
||||
|
||||
} else {
|
||||
// draw
|
||||
draw(low, high, width, height, values);
|
||||
}
|
||||
|
||||
System.out.println("------------------------Frame " + frameCounter + " finished------------------------");
|
||||
|
||||
zoom *= zoomSpeed;
|
||||
}
|
||||
|
||||
// TIME
|
||||
long endtime = System.currentTimeMillis();
|
||||
long completionTimeLong = endtime - startTime;
|
||||
double completionTimeSec = (double) completionTimeLong / 1000.0;
|
||||
System.out.println("Calculated " + frames + " frame/s. Process took " + completionTimeSec + "s");
|
||||
|
||||
}
|
||||
|
||||
static void draw(char low, char high, int width, int height, double[][] values) {
|
||||
// a method to draw a filled rectangle of size width * height
|
||||
// each cell can be low or high, and it will show the corresponding char in each cell
|
||||
String line;
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
line = "";
|
||||
// for every line:
|
||||
for (int j = 0; j < width; j++) {
|
||||
// for every char:
|
||||
double value = values[j][i];
|
||||
if (value >= 1) {
|
||||
line += high;
|
||||
} else {
|
||||
line += low;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(line);
|
||||
}
|
||||
}
|
||||
|
||||
static double checkMandelbrot(CNumber number, int iterations, double threshold) {
|
||||
|
||||
// start
|
||||
CNumber n = new CNumber();
|
||||
CNumber c = number;
|
||||
|
||||
// first
|
||||
n = CNumber.add(n, c);
|
||||
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
n = CNumber.add(CNumber.multiply(n, n), c); // CNumber.multiply(n, n)
|
||||
}
|
||||
|
||||
// System.out.println(n.real + " " + n.imag);
|
||||
|
||||
if (n.real < threshold && n.imag < threshold) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void createImage(BufferedImage image, int counter, File f, int width, int height, double[][] values) {
|
||||
|
||||
|
||||
System.out.println("Frame: " + counter + " | Started creating image...");
|
||||
|
||||
|
||||
|
||||
int p0 = getColorAsInt(0, 0, 0, 0);
|
||||
int p1 = getColorAsInt(0, 50, 50, 50);
|
||||
int p2 = getColorAsInt(0, 100, 100, 100);
|
||||
int p3 = getColorAsInt(0, 150, 150, 150);
|
||||
int p4 = getColorAsInt(0, 200, 200, 200);
|
||||
int pMax = getColorAsInt(0, 255, 255, 255);
|
||||
|
||||
int threshold1 = 10;
|
||||
int threshold2 = 20;
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
if (values[i][j] >= 1) {
|
||||
image.setRGB(i, j, p0);
|
||||
} else {
|
||||
image.setRGB(i, j, pMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
f = new File("sequence\\Sequence" + counter + ".png");
|
||||
ImageIO.write(image, "png", f);
|
||||
System.out.println(f.getAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
|
||||
System.out.println("Frame: " + counter + " | Finished creating image.");
|
||||
}
|
||||
|
||||
public static int getColorAsInt(int a, int r, int g, int b) {
|
||||
|
||||
int p1 = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
return p1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ^ originaler italienischer spaghetti code ^
|
||||
111
src/lib.rs
111
src/lib.rs
|
|
@ -1,16 +1,61 @@
|
|||
use std::error::Error;
|
||||
use std::time::SystemTime;
|
||||
use std::ops::{Add, Mul};
|
||||
|
||||
pub fn main(config: Config) -> Result<String, Box<dyn Error>> {
|
||||
let start_time = SystemTime::now().elapsed()?;
|
||||
|
||||
let coords = calculate_sample_points(&config);
|
||||
|
||||
let end_time = SystemTime::now().elapsed()?;
|
||||
println!("Time: {}", end_time.as_micros() - start_time.as_micros());
|
||||
Ok(String::from("hi"))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
fn calculate_sample_points(config: &Config) -> Box<Vec<Vec<CNumber>>> {
|
||||
let step_size_x = 3.0 / config.width;
|
||||
let step_size_y = 2.0 / config.height;
|
||||
|
||||
let offset_x = config.center.real - config.width / 2.0 * step_size_x;
|
||||
let offset_y = -(config.center.imag - config.height / 2.0 * step_size_y);
|
||||
|
||||
let mut coords: Box<Vec<Vec<CNumber>>> =
|
||||
Box::from(vec![vec![CNumber::new(0.0, 0.0); config.width as usize]; config.height as usize]);
|
||||
|
||||
for i in 0..config.width as usize {
|
||||
for j in 0..config.height as usize {
|
||||
coords[j][i].real = offset_x + step_size_x * i as f64;
|
||||
coords[j][i].imag = offset_y + step_size_y * j as f64;
|
||||
}
|
||||
}
|
||||
|
||||
println!("{:?}", coords[0][0]);
|
||||
coords
|
||||
}
|
||||
|
||||
fn check_mandelbrot(number: &CNumber, iter: i32, threshold: f64) -> i32 {
|
||||
let mut n = CNumber::new(0.0, 0.0);
|
||||
let c = number;
|
||||
|
||||
n = n + c;
|
||||
|
||||
for _ in 0..iter {
|
||||
n = n * n + c;
|
||||
}
|
||||
|
||||
if n.real < threshold && n.imag < threshold {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(values: Box<Vec<Vec<i32>>>) -> String {
|
||||
let mut lines = vec![];
|
||||
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct CNumber {
|
||||
real: f64,
|
||||
imag: f64,
|
||||
|
|
@ -20,44 +65,43 @@ impl CNumber {
|
|||
fn new(real: f64, imag: f64) -> CNumber {
|
||||
CNumber { real, imag }
|
||||
}
|
||||
}
|
||||
|
||||
fn add_mut(&mut self, other: CNumber) {
|
||||
self.real += other.real;
|
||||
self.imag += other.imag;
|
||||
}
|
||||
impl Add for &CNumber {
|
||||
type Output = CNumber;
|
||||
|
||||
fn mul_mut(&mut self, other: CNumber) {
|
||||
self.real = self.real * self.real - other.imag * other.imag;
|
||||
self.imag = self.real * other.imag + other.real * self.imag;
|
||||
fn add(&self, b: CNumber) -> Self::Output {
|
||||
let real = self.real + b.real;
|
||||
let imag = self.imag + b.imag;
|
||||
|
||||
CNumber { real, imag }
|
||||
}
|
||||
}
|
||||
|
||||
fn add_c(a: &CNumber, b: &CNumber) -> CNumber {
|
||||
let real = a.real + b.real;
|
||||
let imag = a.imag + b.imag;
|
||||
impl Mul for &CNumber {
|
||||
type Output = CNumber;
|
||||
|
||||
CNumber { real, imag }
|
||||
fn mul(self, b: Self) -> Self::Output {
|
||||
let real = self.real * self.real - b.imag * b.imag;
|
||||
let imag = self.real * b.imag + b.real * self.imag;
|
||||
|
||||
CNumber { real, imag }
|
||||
}
|
||||
}
|
||||
|
||||
fn mul_c(a: &CNumber, b: &CNumber) -> CNumber {
|
||||
let real = a.real * a.real - b.imag * b.imag;
|
||||
let imag = a.real * b.imag + b.real * a.imag;
|
||||
|
||||
CNumber { real, imag }
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
quality: i32,
|
||||
width: i32,
|
||||
threshold: f32,
|
||||
width: f64,
|
||||
threshold: f64,
|
||||
//-- calculated
|
||||
height: i32,
|
||||
height: f64,
|
||||
center: CNumber,
|
||||
iterations: i32,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new(point_number: usize, quality: i32, width: i32, threshold: f32) -> Config{
|
||||
pub fn new(point_number: usize, quality: i32, width: i32, threshold: f32) -> Config {
|
||||
let height = width as f32 * 0.2;
|
||||
|
||||
let interesting_points = vec![CNumber::new(-0.75, 0.0), CNumber::new(-0.77568377, 0.13646737)];
|
||||
|
|
@ -72,8 +116,27 @@ impl Config {
|
|||
};
|
||||
|
||||
Config {
|
||||
quality, width, height: height as i32,
|
||||
center, iterations, threshold,
|
||||
quality,
|
||||
width: width as f64,
|
||||
height: height as f64,
|
||||
center,
|
||||
iterations,
|
||||
threshold: threshold as f64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#[cfg(tests)]
|
||||
mod tests {
|
||||
use crate::{Config, calculate_sample_points};
|
||||
|
||||
#[test]
|
||||
fn correct_size_points() {
|
||||
let config = Config::new(1, 0, 100, 0.0);
|
||||
|
||||
let result = calculate_sample_points(&config);
|
||||
|
||||
result[0][0];
|
||||
result[0][99];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,10 @@
|
|||
use mandelbrot_set::Config;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let config = Config::new(1, 3, 100, 100.0);
|
||||
|
||||
match mandelbrot_set::main(config) {
|
||||
Ok(s) => println!("{}", s),
|
||||
Err(e) => println!("Error: {}", e)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue