package main | |
// Renders a series of julia_n.pngs which can be zipped together into a gif. | |
// | |
// Example usage: | |
// go run julia.go | |
// convert /tmp/julia*.png -loop 0 animation.gif | |
import ( | |
"fmt" | |
"github.com/fogleman/gg" | |
"image/color" | |
"math" | |
"math/cmplx" | |
) | |
const ( | |
// Variables for the Julia set. | |
kConst complex128 = -0.8 + 0.156i | |
kThreshold float64 = 1.9 | |
// The scaling factor between pixels and floating point coordinates. A higher | |
// number means a more zoomed-in image. | |
kScaling float64 = 600.0 | |
// The dimensions of the image. | |
kDim int = 500 | |
// The number of frames to render at the most. | |
kSteps int = 50 | |
) | |
// Computes a fractional |mu|-value given the integer number of steps |i| and | |
// the complex value |z|. | |
func Mu(i int, z complex128) float64 { | |
return float64(i) + 1.0 - math.Log(math.Log(cmplx.Abs(z)))/math.Log(2.0) | |
} | |
// Computes the shade for each pixel in a 2D array and returns the maximum | |
// mu-value (shade analogue) encountered during the aforementioned process. | |
func Compute(pixels *[kDim][kDim]float64, steps int) float64 { | |
var max_mu float64 = 0.0 | |
for x := 0; x < kDim; x++ { | |
a := float64(x) / kScaling | |
for y := 0; y < kDim; y++ { | |
b := float64(y) / kScaling | |
z := complex(a, b) | |
for i := 0; i < steps; i++ { | |
z = cmplx.Pow(z, 2) + kConst | |
if cmplx.Abs(z) > kThreshold { | |
var mu float64 = Mu(i, z) | |
if mu > max_mu { | |
max_mu = mu | |
} | |
pixels[x][y] = mu | |
break | |
} | |
} | |
} | |
} | |
return max_mu | |
} | |
// Maps a floating-point number between 0 and 1 to a grayscale color between 0 | |
// and 255. | |
func Shade(n float64) color.Color { | |
return color.Gray{uint8(n * (math.MaxInt8 - 1))} | |
} | |
// Renders a 2D array of pixels to a gg.Context object. | |
func Render(max_mu float64, pixels [kDim][kDim]float64) *gg.Context { | |
dc := gg.NewContext(kDim, kDim) | |
for x := 0; x < kDim; x++ { | |
for y := 0; y < kDim; y++ { | |
dc.SetColor(Shade(pixels[x][y] / max_mu)) | |
dc.SetPixel(x, y) | |
} | |
} | |
dc.SetRGB(0, 0, 0) | |
dc.Fill() | |
return dc | |
} | |
func main() { | |
for f := 0; f < kSteps; f++ { | |
fmt.Printf("Step %v\n", f) | |
var pixels [kDim][kDim]float64 | |
max_mu := Compute(&pixels, f /*steps*/) | |
Render(max_mu, pixels).SavePNG(fmt.Sprintf("/tmp/julia_%v.png", f)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment