working single-threaded
commit
c6ebcfea12
@ -0,0 +1,2 @@
|
||||
*.png
|
||||
target
|
@ -0,0 +1,224 @@
|
||||
[root]
|
||||
name = "mandelbrot"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"image 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "deque"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum_primitive"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gif"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum_primitive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gif 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jpeg-decoder 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"png 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inflate"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lzw"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "miniz-sys"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gcc 0.3.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-bigint 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-complex 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.1.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-bigint 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inflate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-serialize"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "mandelbrot"
|
||||
version = "0.2.0"
|
||||
authors = ["Jim Blandy <jimb@red-bean.com>"]
|
||||
|
||||
[dependencies]
|
||||
num = "0.1.34"
|
||||
image = "0.10.1"
|
@ -0,0 +1,164 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Parse the string `s` as a coordinate pair, like `"400x600"` or `"1.0,0.5"`.
|
||||
///
|
||||
/// Specifically, `s` should have the form <left><sep><right>, where <sep> is
|
||||
/// the character given by the `separator` argument, and <left> and <right> are both
|
||||
/// strings that can be parsed by `T::from_str`.
|
||||
///
|
||||
/// If `s` has the proper form, return `Some<(x, y)>`. If it doesn't parse
|
||||
/// correctly, return `None`.
|
||||
fn parse_pair<T: FromStr>(s: &str, separator: char) -> Option<(T, T)> {
|
||||
match s.find(separator) {
|
||||
None => None,
|
||||
Some(index) => {
|
||||
match (T::from_str(&s[..index]), T::from_str(&s[index + 1..])) {
|
||||
(Ok(l), Ok(r)) => Some((l, r)),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_pair() {
|
||||
assert_eq!(parse_pair::<i32>("", ','), None);
|
||||
assert_eq!(parse_pair::<i32>("10,", ','), None);
|
||||
assert_eq!(parse_pair::<i32>(",10", ','), None);
|
||||
assert_eq!(parse_pair::<i32>("10,20", ','), Some((10, 20)));
|
||||
assert_eq!(parse_pair::<i32>("10,20xy", ','), None);
|
||||
assert_eq!(parse_pair::<f64>("0.5x", 'x'), None);
|
||||
assert_eq!(parse_pair::<f64>("0.5x1.5", 'x'), Some((0.5, 1.5)));
|
||||
}
|
||||
|
||||
/// Return the point on the complex plane corresponding to a given pixel in the
|
||||
/// bitmap.
|
||||
///
|
||||
/// `bounds` is a pair giving the width and height of the bitmap. `pixel` is a
|
||||
/// pair indicating a particular pixel in that bitmap. The `upper_left` and
|
||||
/// `lower_right` parameters are points on the complex plane designating the
|
||||
/// area our bitmap covers.
|
||||
fn pixel_to_point(bounds: (usize, usize),
|
||||
pixel: (usize, usize),
|
||||
upper_left: (f64, f64),
|
||||
lower_right: (f64, f64))
|
||||
-> (f64, f64)
|
||||
{
|
||||
// It might be nicer to find the position of the *middle* of the pixel,
|
||||
// instead of its upper left corner, but this is easier to write tests for.
|
||||
let (width, height) = (lower_right.0 - upper_left.0,
|
||||
upper_left.1 - lower_right.1);
|
||||
(upper_left.0 + pixel.0 as f64 * width / bounds.0 as f64,
|
||||
upper_left.1 - pixel.1 as f64 * height / bounds.1 as f64)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pixel_to_point() {
|
||||
assert_eq!(pixel_to_point((100, 100), (25, 75),
|
||||
(-1.0, 1.0), (1.0, -1.0)),
|
||||
(-0.5, -0.5));
|
||||
}
|
||||
|
||||
extern crate num;
|
||||
use num::Complex;
|
||||
|
||||
/// Try to determine whether the complex number `c` is in the Mandelbrot set.
|
||||
///
|
||||
/// A number `c` is in the set if, starting with zero, repeatedly squaring and
|
||||
/// adding `c` never causes the number to leave the circle of radius 2 centered
|
||||
/// on the origin; the number instead orbits near the origin forever. (If the
|
||||
/// number does leave the circle, it eventually flies away to infinity.)
|
||||
///
|
||||
/// If after `limit` iterations our number has still not left the circle, return
|
||||
/// `None`; this is as close as we come to knowing that `c` is in the set.
|
||||
///
|
||||
/// If the number does leave the circle before we give up, return `Some(i)`, where
|
||||
/// `i` is the number of iterations it took.
|
||||
fn escapes(c: Complex<f64>, limit: u32) -> Option<u32> {
|
||||
let mut z = Complex { re: 0.0, im: 0.0 };
|
||||
for i in 0..limit {
|
||||
z = z*z + c;
|
||||
if z.norm_sqr() > 4.0 {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Render a rectangle of the Mandelbrot set into a buffer of pixels.
|
||||
///
|
||||
/// The `bounds` argument gives the width and height of the buffer `pixels`,
|
||||
/// which holds one grayscale pixel per byte. The `upper_left` and `lower_right`
|
||||
/// arguments specify points on the complex plane corresponding to the upper
|
||||
/// left and lower right corners of the pixel buffer.
|
||||
fn render(pixels: &mut [u8], bounds: (usize, usize),
|
||||
upper_left: (f64, f64), lower_right: (f64, f64))
|
||||
{
|
||||
assert!(pixels.len() == bounds.0 * bounds.1);
|
||||
|
||||
for r in 0 .. bounds.1 {
|
||||
for c in 0 .. bounds.0 {
|
||||
let point = pixel_to_point(bounds, (c, r),
|
||||
upper_left, lower_right);
|
||||
pixels[r * bounds.0 + c] =
|
||||
match escapes(Complex { re: point.0, im: point.1 }, 255) {
|
||||
None => 0,
|
||||
Some(count) => 255 - count as u8
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern crate image;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Result;
|
||||
use image::png::PNGEncoder;
|
||||
use image::ColorType;
|
||||
|
||||
/// Write the buffer `pixels`, whose dimensions are given by `bounds`, to the
|
||||
/// file named `filename`.
|
||||
fn write_bitmap(filename: &str, pixels: &[u8], bounds: (usize, usize))
|
||||
-> Result<()>
|
||||
{
|
||||
let output = try!(File::create(filename));
|
||||
|
||||
let encoder = PNGEncoder::new(output);
|
||||
try!(encoder.encode(&pixels[..],
|
||||
bounds.0 as u32, bounds.1 as u32,
|
||||
ColorType::Gray(8)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
fn main() {
|
||||
let args : Vec<String> = std::env::args().collect();
|
||||
|
||||
if args.len() != 5 {
|
||||
writeln!(std::io::stderr(),
|
||||
"Usage: mandelbrot FILE PIXELS UPPERLEFT LOWERRIGHT")
|
||||
.unwrap();
|
||||
writeln!(std::io::stderr(),
|
||||
"Example: {} mandel.png 1000x750 -1.20,0.35 -1,0.20",
|
||||
args[0])
|
||||
.unwrap();
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let bounds = parse_pair(&args[2], 'x')
|
||||
.expect("error parsing image dimensions");
|
||||
let upper_left = parse_pair(&args[3], ',')
|
||||
.expect("error parsing upper left corner point");
|
||||
let lower_right = parse_pair(&args[4], ',')
|
||||
.expect("error parsing lower right corner point");
|
||||
|
||||
let mut pixels = vec![0; bounds.0 * bounds.1];
|
||||
render(&mut pixels[..], bounds, upper_left, lower_right);
|
||||
|
||||
write_bitmap(&args[1], &pixels[..], bounds).expect("error writing PNG file");
|
||||
}
|
Loading…
Reference in New Issue