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